Railway Operation Simulator  v2.5.0
A railway simulator for Windows
InterfaceUnit.cpp
Go to the documentation of this file.
1 // InterfaceUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 
27 #include <Classes.hpp>
28 #include <Controls.hpp>
29 #include <StdCtrls.hpp>
30 #include <Forms.hpp>
31 #include <Buttons.hpp>
32 #include <ExtCtrls.hpp>
33 #include <Menus.hpp>
34 #include <Dialogs.hpp>
35 #include <Graphics.hpp>
36 #include <ComCtrls.hpp>
37 #include <fstream>
38 #include <vector>
39 #include <vcl.h>
40 #include <stdio.h>
41 #include <algorithm> //for sort
42 
43 #pragma hdrstop
44 // The above batch of include files above #pragma hdrstop appear in all .cpp files.
45 // They aren't all needed in each case but being together and identical they speed
46 // up compilation considerably (without ~14 min, with ~1 min!). They are used in
47 // conjunction with 'use pre-compiled headers' in the project compiler options.
48 
49 #include "InterfaceUnit.h"
50 #include "GraphicUnit.h"
51 #include "DisplayUnit.h"
52 #include "TextUnit.h"
53 #include "TrainUnit.h"
54 #include "Utilities.h"
55 #include "TrackUnit.h"
56 #include "AboutUnit.h"
57 #include <fstream>
58 #include <dirent.h>
59 #include <Filectrl.hpp> //to check whether directories exist
60 
61 // ---------------------------------------------------------------------------
62 #include <Vcl.HTMLHelpViewer.hpp> //added at v2.0.0 for access to the .chm help file
63 #pragma package(smart_init)
64 #pragma link "Vcl.HTMLHelpViewer" //added at v2.0.0 for access to the .chm help file
65 #pragma resource "*.dfm"
66 
68 
69 // Folder Names
70 const UnicodeString TInterface::RAILWAY_DIR_NAME = "Railways";
71 const UnicodeString TInterface::TIMETABLE_DIR_NAME = "Program timetables";
72 const UnicodeString TInterface::PERFLOG_DIR_NAME = "Performance logs";
73 const UnicodeString TInterface::SESSION_DIR_NAME = "Sessions";
74 const UnicodeString TInterface::IMAGE_DIR_NAME = "Images";
75 const UnicodeString TInterface::FORMATTEDTT_DIR_NAME = "Formatted timetables";
76 const UnicodeString TInterface::USERGRAPHICS_DIR_NAME = "Graphics";
77 
78 // ---------------------------------------------------------------------------
79 
80 __fastcall TInterface::TInterface(TComponent* Owner): TForm(Owner)
81 { // constructor
82  try
83  {
84  Screen->Cursor = TCursor(-11); // Hourglass;
85  DirOpenError = false;
86  AllSetUpFlag = false; // flag to prevent MasterClock from being enabled when application activates if there has been an error during
87  // initial setup
88  // MasterClock->Enabled = false;//keep this stopped until all set up (no effect here as form not yet created, made false in object insp)
89  // Visible = false; //keep the Interface form invisible until all set up (no effect here as form not yet created, made false in object insp)
91  // use GNU Major/Minor/Patch version numbering system, change for each published modification, Dev x = interim internal
92  // development stages (don't show on published versions)
93 
94  // check for presence of directories, creation failure probably indicates that the
95  // working folder is read-only
96  CurDir = GetCurrentDir();
97  if(!DirectoryExists(RAILWAY_DIR_NAME))
98  {
99  if(!CreateDir(RAILWAY_DIR_NAME))
100  {
101  DirOpenError = true;
102  }
103  }
104  if(!DirectoryExists(TIMETABLE_DIR_NAME))
105  {
106  if(!CreateDir(TIMETABLE_DIR_NAME))
107  {
108  DirOpenError = true;
109  }
110  }
111  if(!DirectoryExists(PERFLOG_DIR_NAME))
112  {
113  if(!CreateDir(PERFLOG_DIR_NAME))
114  {
115  DirOpenError = true;
116  }
117  }
118  if(!DirectoryExists(SESSION_DIR_NAME))
119  {
120  if(!CreateDir(SESSION_DIR_NAME))
121  {
122  DirOpenError = true;
123  }
124  }
125  if(!DirectoryExists(IMAGE_DIR_NAME))
126  {
127  if(!CreateDir(IMAGE_DIR_NAME))
128  {
129  DirOpenError = true;
130  }
131  }
132  if(!DirectoryExists(FORMATTEDTT_DIR_NAME))
133  {
134  if(!CreateDir(FORMATTEDTT_DIR_NAME))
135  {
136  DirOpenError = true;
137  }
138  }
139  if(!DirectoryExists(USERGRAPHICS_DIR_NAME))
140  {
141  if(!CreateDir(USERGRAPHICS_DIR_NAME))
142  {
143  DirOpenError = true;
144  }
145  }
146  if(DirOpenError)
147  {
148  ShowMessage("Failed to create one or more of folders: " + RAILWAY_DIR_NAME + ", " + TIMETABLE_DIR_NAME + ", " + PERFLOG_DIR_NAME + ", " +
150  "program operation may be restricted");
151  }
152 // ShowMessage("NOTE: APPDEACTIVATE etc Disabled in FormCreate");
153  SaveRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
154  LoadRailwayDialog->InitialDir = CurDir + "\\" + RAILWAY_DIR_NAME;
155  TimetableDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
156  SaveTTDialog->InitialDir = CurDir + "\\" + TIMETABLE_DIR_NAME;
157  LoadSessionDialog->InitialDir = CurDir + "\\" + SESSION_DIR_NAME;
158  LoadUserGraphicDialog->InitialDir = CurDir + "\\" + USERGRAPHICS_DIR_NAME;
159 
160  Application->HelpFile = AnsiString(CurDir + "\\Help.chm"); // added at v2.0.0 for .chm help file
161 
162  MainMenu1->AutoHotkeys = maManual; // Embarcadero mod: to suppress '&' inclusion for underlined characters in menu items
163  PopupMenu->AutoHotkeys = maManual; // as above
164 
165  Utilities = new TUtilities;
166  RailGraphics = new TRailGraphics();
167 
168  int DispW = (Screen->Width - 64) / 16; // will truncate down to a multiple of 16 OK here as screen dimensions are accurate
169  int DispH = (Screen->Height - 192) / 16; // Interface dimensions are 16 too wide & 14 short in height
170  MainScreen->Width = DispW * 16;
171  MainScreen->Height = DispH * 16;
172 
175  Utilities->ScreenElementWidth = DispW;
177  HiddenScreen = new TImage(Interface);
178  HiddenScreen->Width = MainScreen->Width;
179  HiddenScreen->Height = MainScreen->Height;
183  Track = new TTrack;
184  AllRoutes = new TAllRoutes;
189  SelectBitmap = new Graphics::TBitmap;
190  SelectBitmap->PixelFormat = pf8bit;
191  SelectBitmap->Transparent = true;
196 
197  TrackInfoOnOffMenuItem->Caption = "Show"; // added here at v1.2.0 because dropped from ResetAll()
198  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status"; // changed at v2.0.0 so normally visible
199  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable"; // as above
200  ResetAll(0);
201 
202  TempTTFileName = "";
203 
208 
209  RouteFlashDuration = 0.0;
210  PointsFlashDuration = 0.0;
211 
212  FloatingLabel->Color = clB4G5R5;
213  TrackElementPanel->Color = clB5G5R4;
214  InfoPanel->Color = clB4G5R5;
215 
216  SpeedButton1->Glyph->LoadFromResourceName(0, "gl1");
217  SpeedButton2->Glyph->LoadFromResourceName(0, "gl2");
218  SpeedButton3->Glyph->LoadFromResourceName(0, "gl3");
219  SpeedButton4->Glyph->LoadFromResourceName(0, "gl4");
220  SpeedButton5->Glyph->LoadFromResourceName(0, "gl5");
221  SpeedButton6->Glyph->LoadFromResourceName(0, "gl6");
222  SpeedButton7->Glyph->LoadFromResourceName(0, "gl7");
223  SpeedButton8->Glyph->LoadFromResourceName(0, "gl8");
224  SpeedButton9->Glyph->LoadFromResourceName(0, "gl9");
225  SpeedButton10->Glyph->LoadFromResourceName(0, "gl10");
226  SpeedButton11->Glyph->LoadFromResourceName(0, "gl11");
227  SpeedButton12->Glyph->LoadFromResourceName(0, "gl12");
228  SpeedButton13->Glyph->LoadFromResourceName(0, "gl13");
229  SpeedButton14->Glyph->LoadFromResourceName(0, "gl14");
230  SpeedButton15->Glyph->LoadFromResourceName(0, "gl15");
231  SpeedButton16->Glyph->LoadFromResourceName(0, "gl16");
232  SpeedButton18->Glyph->LoadFromResourceName(0, "gl18");
233  SpeedButton19->Glyph->LoadFromResourceName(0, "gl19");
234  SpeedButton20->Glyph->LoadFromResourceName(0, "gl20");
235  SpeedButton21->Glyph->LoadFromResourceName(0, "gl21");
236  SpeedButton22->Glyph->LoadFromResourceName(0, "gl22");
237  SpeedButton23->Glyph->LoadFromResourceName(0, "gl23");
238  SpeedButton24->Glyph->LoadFromResourceName(0, "gl24");
239  SpeedButton25->Glyph->LoadFromResourceName(0, "gl25");
240  SpeedButton26->Glyph->LoadFromResourceName(0, "gl26");
241  SpeedButton27->Glyph->LoadFromResourceName(0, "gl27");
242  SpeedButton28->Glyph->LoadFromResourceName(0, "gl28");
243  SpeedButton29->Glyph->LoadFromResourceName(0, "gl29");
244  SpeedButton30->Glyph->LoadFromResourceName(0, "gl30");
245  SpeedButton31->Glyph->LoadFromResourceName(0, "gl31");
246  SpeedButton32->Glyph->LoadFromResourceName(0, "gl32");
247  SpeedButton33->Glyph->LoadFromResourceName(0, "gl33");
248  SpeedButton34->Glyph->LoadFromResourceName(0, "gl34");
249  SpeedButton35->Glyph->LoadFromResourceName(0, "gl35");
250  SpeedButton36->Glyph->LoadFromResourceName(0, "gl36");
251  SpeedButton37->Glyph->LoadFromResourceName(0, "gl37");
252  SpeedButton38->Glyph->LoadFromResourceName(0, "gl38");
253  SpeedButton39->Glyph->LoadFromResourceName(0, "gl39");
254  SpeedButton40->Glyph->LoadFromResourceName(0, "gl40");
255  SpeedButton41->Glyph->LoadFromResourceName(0, "gl41");
256  SpeedButton42->Glyph->LoadFromResourceName(0, "gl42");
257  SpeedButton43->Glyph->LoadFromResourceName(0, "gl43");
258  SpeedButton44->Glyph->LoadFromResourceName(0, "gl44");
259  SpeedButton45->Glyph->LoadFromResourceName(0, "gl45");
260  SpeedButton46->Glyph->LoadFromResourceName(0, "gl46");
261  SpeedButton47->Glyph->LoadFromResourceName(0, "gl47");
262  SpeedButton48->Glyph->LoadFromResourceName(0, "gl48");
263  SpeedButton49->Glyph->LoadFromResourceName(0, "gl49");
264  SpeedButton50->Glyph->LoadFromResourceName(0, "gl50");
265  SpeedButton51->Glyph->LoadFromResourceName(0, "gl51");
266  SpeedButton52->Glyph->LoadFromResourceName(0, "gl52");
267  SpeedButton53->Glyph->LoadFromResourceName(0, "gl53");
268  SpeedButton54->Glyph->LoadFromResourceName(0, "gl54");
269  SpeedButton55->Glyph->LoadFromResourceName(0, "gl55");
270  SpeedButton56->Glyph->LoadFromResourceName(0, "gl56");
271  SpeedButton57->Glyph->LoadFromResourceName(0, "gl57");
272  SpeedButton58->Glyph->LoadFromResourceName(0, "gl58");
273  SpeedButton59->Glyph->LoadFromResourceName(0, "gl59");
274  SpeedButton60->Glyph->LoadFromResourceName(0, "gl60");
275  SpeedButton61->Glyph->LoadFromResourceName(0, "gl61");
276  SpeedButton62->Glyph->LoadFromResourceName(0, "gl62");
277  SpeedButton63->Glyph->LoadFromResourceName(0, "gl63");
278  SpeedButton64->Glyph->LoadFromResourceName(0, "gl64");
279  SpeedButton65->Glyph->LoadFromResourceName(0, "gl65");
280  SpeedButton66->Glyph->LoadFromResourceName(0, "gl66");
281  SpeedButton67->Glyph->LoadFromResourceName(0, "gl67");
282  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68");
283  SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
284  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70");
285  SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
286  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72");
287  SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
288  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74");
289  SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
290  SpeedButton76->Glyph->LoadFromResourceName(0, "gl76");
291  SpeedButton77->Glyph->LoadFromResourceName(0, "gl77");
292  SpeedButton78->Glyph->LoadFromResourceName(0, "gl78");
293  SpeedButton79->Glyph->LoadFromResourceName(0, "gl79");
294  SpeedButton80->Glyph->LoadFromResourceName(0, "gl80");
295  SpeedButton81->Glyph->LoadFromResourceName(0, "gl81");
296  SpeedButton82->Glyph->LoadFromResourceName(0, "gl82");
297  SpeedButton83->Glyph->LoadFromResourceName(0, "gl83");
298  SpeedButton84->Glyph->LoadFromResourceName(0, "gl84");
299  SpeedButton85->Glyph->LoadFromResourceName(0, "gl85");
300  SpeedButton86->Glyph->LoadFromResourceName(0, "gl86");
301  SpeedButton87->Glyph->LoadFromResourceName(0, "gl87");
302  SpeedButton88->Glyph->LoadFromResourceName(0, "gl88set");
303  SpeedButton89->Glyph->LoadFromResourceName(0, "gl89set");
304  SpeedButton90->Glyph->LoadFromResourceName(0, "gl90set");
305  SpeedButton91->Glyph->LoadFromResourceName(0, "gl91set");
306  SpeedButton92->Glyph->LoadFromResourceName(0, "gl92set");
307  SpeedButton93->Glyph->LoadFromResourceName(0, "gl93set");
308  SpeedButton94->Glyph->LoadFromResourceName(0, "gl94set");
309  SpeedButton95->Glyph->LoadFromResourceName(0, "gl95set");
310  SpeedButton96->Glyph->LoadFromResourceName(0, "ConcourseGlyph");
311  SpeedButton97->Glyph->LoadFromResourceName(0, "gl97");
312  SpeedButton98->Glyph->LoadFromResourceName(0, "gl98");
313  SpeedButton99->Glyph->LoadFromResourceName(0, "gl99");
314  SpeedButton100->Glyph->LoadFromResourceName(0, "gl100");
315  SpeedButton101->Glyph->LoadFromResourceName(0, "gl101");
316  SpeedButton102->Glyph->LoadFromResourceName(0, "gl102");
317  SpeedButton103->Glyph->LoadFromResourceName(0, "gl103");
318  SpeedButton104->Glyph->LoadFromResourceName(0, "gl104");
319  SpeedButton105->Glyph->LoadFromResourceName(0, "gl105");
320  SpeedButton106->Glyph->LoadFromResourceName(0, "gl106");
321  SpeedButton107->Glyph->LoadFromResourceName(0, "gl107");
322  SpeedButton108->Glyph->LoadFromResourceName(0, "gl108");
323  SpeedButton109->Glyph->LoadFromResourceName(0, "gl109");
324  SpeedButton110->Glyph->LoadFromResourceName(0, "gl110");
325  SpeedButton111->Glyph->LoadFromResourceName(0, "gl111");
326  SpeedButton112->Glyph->LoadFromResourceName(0, "gl112");
327  SpeedButton113->Glyph->LoadFromResourceName(0, "gl113");
328  SpeedButton114->Glyph->LoadFromResourceName(0, "gl114");
329  SpeedButton115->Glyph->LoadFromResourceName(0, "gl115");
330  SpeedButton116->Glyph->LoadFromResourceName(0, "gl116");
331  SpeedButton117->Glyph->LoadFromResourceName(0, "gl117");
332  SpeedButton118->Glyph->LoadFromResourceName(0, "gl118");
333  SpeedButton119->Glyph->LoadFromResourceName(0, "gl119");
334  SpeedButton120->Glyph->LoadFromResourceName(0, "gl120");
335  SpeedButton121->Glyph->LoadFromResourceName(0, "gl121");
336  SpeedButton122->Glyph->LoadFromResourceName(0, "gl122");
337  SpeedButton123->Glyph->LoadFromResourceName(0, "gl123");
338  SpeedButton124->Glyph->LoadFromResourceName(0, "gl124");
339  SpeedButton125->Glyph->LoadFromResourceName(0, "gl125");
340  SpeedButton126->Glyph->LoadFromResourceName(0, "gl126");
341  SpeedButton127->Glyph->LoadFromResourceName(0, "gl127");
342  SpeedButton128->Glyph->LoadFromResourceName(0, "gl128");
343  SpeedButton129->Glyph->LoadFromResourceName(0, "gl129");
344  SpeedButton130->Glyph->LoadFromResourceName(0, "gl130");
345  SpeedButton131->Glyph->LoadFromResourceName(0, "gl131");
346  SpeedButton132->Glyph->LoadFromResourceName(0, "gl132");
347  SpeedButton133->Glyph->LoadFromResourceName(0, "gl133");
348  SpeedButton134->Glyph->LoadFromResourceName(0, "gl134");
349  SpeedButton135->Glyph->LoadFromResourceName(0, "gl135");
350  SpeedButton136->Glyph->LoadFromResourceName(0, "gl136");
351  SpeedButton137->Glyph->LoadFromResourceName(0, "gl137");
352  SpeedButton138->Glyph->LoadFromResourceName(0, "gl138");
353  SpeedButton139->Glyph->LoadFromResourceName(0, "gl139");
354  SpeedButton140->Glyph->LoadFromResourceName(0, "gl140");
355  SpeedButton141->Glyph->LoadFromResourceName(0, "gl141");
356  SpeedButton142->Glyph->LoadFromResourceName(0, "gl142");
357  SpeedButton143->Glyph->LoadFromResourceName(0, "gl143");
358  SpeedButton145->Glyph->LoadFromResourceName(0, "gl145");
359  SpeedButton146->Glyph->LoadFromResourceName(0, "gl146");
360  // below not in RailGraphics
361  SpeedButton144->Glyph->LoadFromResourceName(0, "LCGlyph");
362 
363  AddPrefDirButton->Glyph->LoadFromResourceName(0, "AddPrefDir");
364  AddTextButton->Glyph->LoadFromResourceName(0, "AddText");
365  AddTrackButton->Glyph->LoadFromResourceName(0, "AddTrack");
366  AutoSigsButton->Glyph->LoadFromResourceName(0, "AutoSig");
367  CallingOnButton->Glyph->LoadFromResourceName(0, "CallingOn");
368  DeleteAllPrefDirButton->Glyph->LoadFromResourceName(0, "ClearAllPrefDir");
369  DeleteOnePrefDirButton->Glyph->LoadFromResourceName(0, "ClearOnePrefDir");
370  ExitOperationButton->Glyph->LoadFromResourceName(0, "Exit");
371  ExitPrefDirButton->Glyph->LoadFromResourceName(0, "Exit");
372  ExitTrackButton->Glyph->LoadFromResourceName(0, "Exit");
373  ExitTTModeButton->Glyph->LoadFromResourceName(0, "Exit");
374  FontButton->Glyph->LoadFromResourceName(0, "FontGraphic");
375  HomeButton->Glyph->LoadFromResourceName(0, "Home");
376  LocationNameButton->Glyph->LoadFromResourceName(0, "NameLocs");
377  MoveTextOrGraphicButton->Glyph->LoadFromResourceName(0, "MoveTextOrGraphic");
378  NewHomeButton->Glyph->LoadFromResourceName(0, "NewHome");
379  UnrestrictedButton->Glyph->LoadFromResourceName(0, "NonSig");
380  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
381  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
382  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
383  PresetAutoSigRoutesButton->Glyph->LoadFromResourceName(0, "PresetAutoSigRoutes");
384  RouteCancelButton->Glyph->LoadFromResourceName(0, "RouteCancel");
385  SaveRailwayPDPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // PrefDirPanel
386  SaveRailwayBaseModeButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // OperatingPanel
387  SaveRailwayTBPButton->Glyph->LoadFromResourceName(0, "SaveRailway"); // TrackBuildPanel
388  SaveSessionButton->Glyph->LoadFromResourceName(0, "SaveSession");
389  ScreenDownButton->Glyph->LoadFromResourceName(0, "BlackArrowDown");
390  ScreenGridButton->Glyph->LoadFromResourceName(0, "ScreenGrid");
391  ScreenLeftButton->Glyph->LoadFromResourceName(0, "BlackArrowLeft");
392  ScreenRightButton->Glyph->LoadFromResourceName(0, "BlackArrowRight");
393  ScreenUpButton->Glyph->LoadFromResourceName(0, "BlackArrowUp");
394  SetGapsButton->Glyph->LoadFromResourceName(0, "ConnectGaps");
395  SetLengthsButton->Glyph->LoadFromResourceName(0, "SetDists");
396  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
397  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect"); // new at version 0.6
398  SigPrefButton->Glyph->LoadFromResourceName(0, "PrefSig");
399  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
400  TrackOKButton->Glyph->LoadFromResourceName(0, "Validate");
401  TTClockAdjButton->Glyph->LoadFromResourceName(0, "TTClock");
402  UserGraphicButton->Glyph->LoadFromResourceName(0, "PictureImage");
403 
404  BufferAttentionImage->Picture->Bitmap->LoadFromResourceName(0, "BufferWarning");
405  CallOnImage->Picture->Bitmap->LoadFromResourceName(0, "CallingOn");
406  CrashImage->Picture->Bitmap->LoadFromResourceName(0, "CrashWarning");
407  DerailImage->Picture->Bitmap->LoadFromResourceName(0, "DerailWarning");
408  SignalStopImage->Picture->Bitmap->LoadFromResourceName(0, "SignalStopWarning");
409  SPADImage->Picture->Bitmap->LoadFromResourceName(0, "SPADWarning");
410  TrainFailedImage->Picture->Bitmap->LoadFromResourceName(0, "TrainFailedWarning"); // new at v2.4.0
411 
412  DistanceKey->Picture->Bitmap->LoadFromResourceName(0, "DistanceKey");
413  PrefDirKey->Picture->Bitmap->LoadFromResourceName(0, "PrefDirKey");
414 
415  TrackLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackLinkedGraphic");
416  TrackNotLinkedImage->Picture->Bitmap->LoadFromResourceName(0, "TrackNotLinkedGraphic");
417  GapsNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsNotSetGraphic");
418  GapsSetImage->Picture->Bitmap->LoadFromResourceName(0, "GapsSetGraphic");
419  LocationNamesNotSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesNotSetGraphic");
420  LocationNamesSetImage->Picture->Bitmap->LoadFromResourceName(0, "LocNamesSetGraphic");
421 
422  SigsOnLeftImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
423  SigsOnLeftImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnLeft");
424  SigsOnLeftImage1->Transparent = true;
425  SigsOnLeftImage2->Transparent = true;
426  SigsOnLeftImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
427  SigsOnLeftImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
428  SigsOnRightImage1->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
429  SigsOnRightImage2->Picture->Bitmap->LoadFromResourceName(0, "SigsOnRight");
430  SigsOnRightImage1->Transparent = true;
431  SigsOnRightImage2->Transparent = true;
432  SigsOnRightImage1->Picture->Bitmap->TransparentColor = clB5G5R5;
433  SigsOnRightImage2->Picture->Bitmap->TransparentColor = clB5G5R5;
434 
435 /* Don't need this - load icon directly into both Interface form & Application (via Project - Options - Application - Load Icon)
436  RailwayIcon = new TPicture;
437  RailwayIcon->Icon->LoadFromResourceName(0, "Icon1.ico");
438  Icon = RailwayIcon->Icon;
439  Application->Icon = RailwayIcon->Icon;
440 */
441 
442  AnsiString NL = '\n';
443  const AnsiString TTLabelStr1 = "Start new train" + NL + "Start new service from a split" + NL + "Start new service from another service" + NL +
444  "Start new non-repeating shuttle finish service" + NL + "Start new shuttle train at a timetabled stop" + NL +
445  "Start new shuttle service from a feeder";
446 
447  const AnsiString TTLabelStr2 = "Pass" + NL + "Be joined by another train" + NL + "Front split" + NL + "Rear split" + NL + "Change direction of train";
448 
449  const AnsiString TTLabelStr3 = "Finish && form a new service" + NL + "Finish && join another train" + NL + "Finish && exit railway" + NL +
450  "Finish && repeat shuttle, finally remain here" + NL + "Finish && repeat shuttle, finally form a finishing service" + NL +
451  "Finish non-repeating shuttle feeder service" + NL + "Finish && remain here";
452 
453  const AnsiString TTLabelStr4 = "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL +
454  "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + "HH:MM" + NL + " " + NL + "R";
455 
456  const AnsiString TTLabelStr5 = "HH:MM ';' Location" + NL + "HH:MM ';' HH:MM ';' Location";
457 
458  const AnsiString TTLabelStr6 = "+ rear element ID - space - front element ID [+ optional ';S']" + NL + "+ ref. of the train that splits" + NL +
459  "+ other service ref." + NL + "+ shuttle service ref." + NL + "+ rear element ID - space - front element ID ';' linked shuttle ref." + NL +
460  "+ linked shuttle service ref. ';' feeder service ref." + NL + "+ location" + NL + "+ joining train ref." + NL + "+ new service ref." + NL +
461  "+ new service ref." + NL + " " + NL + "+ new service ref." + NL + "+ ref. of train to join" + NL +
462  "+ list of valid exit element IDs (at least 1) separated by spaces" + NL + "+ linked shuttle service ref.";
463 
464  const AnsiString TTLabelStr7 = "Arrival OR departure time (program will determine which from the context) + location." + NL +
465  "Arrival time, departure time (with no events between) + location";
466 
467  const AnsiString TTLabelStr9 = "Timetable entries" + NL + "(service references etc.)";
468  const AnsiString TTLabelStr11 = "Timetable" + NL + "start time";
469 
470  const AnsiString TTLabelStr12 = "NB: WITHIN SERVICES commas must" + NL + "not be used (have special meanings)," + NL +
471  "and semicolons may only be used to" + NL + "separate service components.";
472 
473  const AnsiString TTLabelStr13 = "+ linked shuttle service ref. ';' finishing service ref." + NL + "+ linked shuttle service ref.";
474 
475  const AnsiString TTLabelStr15 = "Repeat the service + ';' minutes between repeats ';' digit increment ';' number of repeats (last line of service)";
476 
477  TTLabel1->Caption = TTLabelStr1;
478  TTLabel2->Caption = TTLabelStr2;
479  TTLabel3->Caption = TTLabelStr3;
480  TTLabel4->Caption = TTLabelStr4;
481  TTLabel5->Caption = TTLabelStr5;
482  TTLabel6->Caption = TTLabelStr6;
483  TTLabel7->Caption = TTLabelStr7;
484  TTLabel9->Caption = TTLabelStr9;
485  TTLabel11->Caption = TTLabelStr11;
486  TTLabel12->Caption = TTLabelStr12;
487  TTLabel13->Caption = TTLabelStr13;
488  TTLabel15->Caption = TTLabelStr15;
489 
490  // pick up transparent colour from file if there is one & set it to the stored value if it's valid else set to black
491 
492  AnsiString ColourStr = "";
493  std::ifstream ColFile((CurDir + "\\Background.col").c_str());
494  if(ColFile.fail())
495  {
496  Utilities->clTransparent = clB0G0R0; // default black background;
497  }
498  else
499  {
500  if(!(Utilities->CheckAndReadFileString(ColFile, ColourStr)))
501  {
502  Utilities->clTransparent = clB0G0R0; // default black background;
503  }
504  else if((ColourStr != "white") && (ColourStr != "black") && (ColourStr != "blue"))
505  {
506  Utilities->clTransparent = clB0G0R0; // default black background;
507  }
508  else
509  {
510  if(ColourStr == "white")
511  {
512  Utilities->clTransparent = TColor(0xFFFFFF);
513  }
514  else if(ColourStr == "blue")
515  {
516  Utilities->clTransparent = TColor(0x330000);
517  }
518  else
519  {
520  Utilities->clTransparent = TColor(0);
521  }
522  ColFile.close(); // added at v2.3.0, should have been in earlier
523  }
524  }
525 
526  Utilities->RHSignalFlag = false; // new at v2.3.0 for RH signals, always left hand on startup
527  AnsiString RHSigStr = "";
528  std::ifstream SignalFile((CurDir + "\\Signal.hnd").c_str());
529  if(SignalFile.fail())
530  {
531  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
532  SigsOnLeftImage1->Visible = true;
533  SigsOnLeftImage2->Visible = true;
534  SigsOnRightImage1->Visible = false;
535  SigsOnRightImage2->Visible = false;
536  SignalFile.close(); // close ifstream & open ofstream
537  std::ofstream SignalFile((CurDir + "\\Signal.hnd").c_str());
538  if(!SignalFile.fail()) // if it does fail then it will revert to LHS anyway on next load unless select RH sigs
539  {
540  Utilities->SaveFileString(SignalFile, "LHSignals");
541  }
542  SignalFile.close();
543  }
544  else
545  {
546  if(Utilities->CheckAndReadFileString(SignalFile, RHSigStr)) // if it fails then do nothing
547  {
548  if(RHSigStr == "RHSignals")
549  {
550  RailGraphics->ConvertSignalsToOppositeHand(1); // always left hand initially when start program
551  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
553  {
555  }
556  else
557  {
559  }
560  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
561  SigsOnLeftImage1->Visible = false;
562  SigsOnLeftImage2->Visible = false;
563  SigsOnRightImage1->Visible = true;
564  SigsOnRightImage2->Visible = true;
565  SignalFile.close();
566  }
567  else
568  {
569  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
570  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
571  SigsOnLeftImage1->Visible = true;
572  SigsOnLeftImage2->Visible = true;
573  SigsOnRightImage1->Visible = false;
574  SigsOnRightImage2->Visible = false;
575  SignalFile.close(); // close ifstream & open ofstream
576  std::ofstream SignalFile((CurDir + "\\Signal.hnd").c_str());
577  if(!SignalFile.fail()) // if it does fail then it will revert to LHS anyway on next load unless select RH sigs
578  {
579  Utilities->SaveFileString(SignalFile, "LHSignals");
580  }
581  SignalFile.close();
582  }
583  }
584  }
585 
586  SelectBitmap->TransparentColor = Utilities->clTransparent;
587  RailGraphics->ChangeAllTransparentColours(Utilities->clTransparent, clB5G5R5); // original colour is as loaded at this stage - white
589  TextBox->Color = clB3G3R3;
591 
592  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
593  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
594 
595  std::ifstream SplashFile((CurDir + "\\GNU").c_str());
596  if(SplashFile.fail())
597  {
598  ShowMessage(
599  "This program is free software released under the terms of the GNU General Public License Version 3, as published by the Free Software Foundation. It may be used or redistributed in accordance with that license and is released in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details - you should have received a copy along with this program but if not see <http://www.gnu.org/licenses/>.");
600  std::ofstream SplashFile((CurDir + "\\GNU").c_str());
601  if(!SplashFile.fail())
602  SplashFile.close();
603  }
604 
605  if((Screen->Width < 1024) || (Screen->Height < 768))
606  {
607  ShowMessage("Please note that this program works best with a screen resolution of at least 1024 x 768. Please change if possible");
608  }
609 
610  SkipFormResizeEvent = true; // added at v2.1.0
611  MasterClock->Enabled = true;
612  Visible = true; // make Interface form visible (set to false at design time) autocalls FormResize so it is skipped
613  WindowState = wsMaximized; // need this for full screen at start autocalls FormResize so it is skipped
614  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30; // new v2.4.0 30 is to place it above the positional panel
615  // has to come after Visible = true or doesn't show
616  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
617  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
618  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
619  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
620  AllSetUpFlag = true;
621  MissedTicks = 0;
622  TotalTicks = 0;
624  SetLevel1Mode(131); // to reset background colour mode menu choices
625  Screen->Cursor = TCursor(-2); // Arrow
626  SkipFormResizeEvent = false; // added at v2.1.0
627  SelectedGraphicFileName = ""; // only set to null here so always has a value after use LoadUserGraphic
628 
629  FloatingPanel->Color = TColor(0xF0FFFF); // new v2.2.0, corrects floating panel background colour in Windows 10
630  PerformancePanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
631  OperatorActionPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
632  DevelopmentPanel->Color = TColor(0xCCCCCC); // new v2.2.0 as above
633  TTStartTimeBox->Color = TColor(0x99FFFF); // cream
634  HighlightPanel->Color = TColor(0x33CCFF);
636  MTBFEditBox->Visible = false; // new at v2.4.0
637  MTBFLabel->Visible = false;
640  TTStartTimePtr = 0;
641  TTFirstServicePtr = 0;
642  TTLastServicePtr = 0;
643  ConflictPanel->Visible = false;
644  TTClockAdjustWarningPanel->Visible = false;
645  TTClockAdjustWarningHide = false;
646  LastNonCtrlOrShiftKeyDown = -1; //set to no key
647 
648  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
649 
650  // below added at v2.4.0 so able to load session files with the correct decimal point
651  Utilities->DecimalPoint = '.'; // default case is full stop
652  char *LocalNumericInformation = setlocale(LC_NUMERIC, ""); // need this to set lconv to the environment's numeric format
654  if(LocalNumericInformation == "") // call failed, don't change decimal point in Utilities.cpp
655  {
656  Utilities->SetLocaleResultOK = false;
657  }
658  struct lconv Locale; // store this structure in memory (accessed via locale.h in Utilities.h)
659  struct lconv *conv = &Locale;
660  // read the locality conversion structure
661  conv = localeconv(); // this is what updates the structure
662  Utilities->DecimalPoint = conv->decimal_point[0];
663  }
664 
665  catch(const EFOpenError &e)
666  {
667  TMsgDlgButtons But;
668  But << mbOK;
669  MessageDlg(e.Message + " - program must terminate", mtError, But, 0);
670  Application->Terminate();
671  }
672 
673  catch(const Exception &e)
674  {
675  TMsgDlgButtons But;
676  But << mbOK;
677  AnsiString Message = "A fatal error occurred during the program setup process, the program must terminate. Message = " + e.Message;
678  MessageDlg(Message, mtError, But, 0); // this message given first in case can't create the error log
679  ErrorLog(115, e.Message);
680  Application->Terminate();
681  }
682 }
683 
684 // ---------------------------------------------------------------------------
685 
687 { // destructor
688  try
689  {
690  SkipFormResizeEvent = true; // added at v2.1.0
691  delete NonSigRouteStartMarker;
692  delete SigRouteStartMarker;
693  delete AutoRouteStartMarker;
694  delete PointFlash;
695  delete SelectBitmap;
696  delete TrainController;
697  delete EveryPrefDir;
698  delete ConstructRoute;
699  delete ConstructPrefDir;
700  delete AllRoutes;
701  delete Track;
702  delete TextHandler;
703  delete HiddenDisplay;
704  delete HiddenScreen;
705  delete Display;
706  delete RailGraphics;
707  delete Utilities;
708  DeleteFile(TempTTFileName); //added after v2.4.3 to prevent temporary files building up
709  }
710  catch(const Exception &e)
711  {
712  ErrorLog(116, e.Message);
713  }
714 }
716 
717 // ---------------------------------------------------------------------------
718 
719 void __fastcall TInterface::FormCreate(TObject *Sender)
720 { // these functions have to be defined here to take effect when application activated & deactivated
721  try
722  {
723  Application->OnDeactivate = AppDeactivate;
724  Application->OnActivate = AppActivate;
725  }
726  catch(const Exception &e)
727  {
728  ErrorLog(117, e.Message);
729  }
730 }
731 
732 // ---------------------------------------------------------------------------
733 
734 void __fastcall TInterface::AppDeactivate(TObject *Sender)
735 { // pause operation if operating & stop the master clock
736  try
737  {
739  {
740  if(Track->RouteFlashFlag) // in case route building - cancels the route, freezes otherwise - reported
741  { // by Matt Blades 30/06/11
745  Screen->Cursor = TCursor(-2); // Arrow
746  Track->RouteFlashFlag = false;
747  ClearandRebuildRailway(48); // to get rid of displayed route
748  }
749  if(Track->PointFlashFlag)
750  // added at v1.3.1 to prevent lockup for flashing points when deactivates. Notified by Ian Walker in his email of 25/03/13.
751  {
753  Track->PointFlashFlag = false;
755  Screen->Cursor = TCursor(-2); // Arrow
756  }
759  }
760  MasterClock->Enabled = false;
761  }
762  catch(const Exception &e)
763  {
764  ErrorLog(118, e.Message);
765  }
766 }
767 
768 // ---------------------------------------------------------------------------
769 
770 void __fastcall TInterface::AppActivate(TObject *Sender)
771 { // restart the master clock providing Interface constructor has run
772  try
773  {
774  if(AllSetUpFlag)
775  {
776  MasterClock->Enabled = true;
777  }
778  }
779  catch(const Exception &e)
780  {
781  ErrorLog(119, e.Message);
782  }
783 }
784 
785 // ---------------------------------------------------------------------------
786 
787 UnicodeString TInterface::GetVersion()
788 {
789  DWORD VersionHandle;
790  DWORD VersionSize;
791  LPBYTE pBuffer;
792  UnicodeString strVersion = L"N/A";
793 
794  VersionSize = GetFileVersionInfoSizeW(Application->ExeName.c_str(), &VersionHandle);
795  if(VersionSize)
796  {
797  pBuffer = new BYTE[VersionSize];
798 
799  if(GetFileVersionInfoW(Application->ExeName.c_str(), VersionHandle, VersionSize, pBuffer))
800  {
801  VS_FIXEDFILEINFO *fi;
802  UINT buflen;
803 
804  // uncomment strVersion and HIWORD alternates below when future CI implemented: sas@2.1.0
805  if(VerQueryValueW(pBuffer, L"\\", (void**)&fi, &buflen))
806  {
807  // strVersion.sprintf(L"%d.%d.%d (Build %d)",
808  strVersion.sprintf(L"%d.%d.%d", HIWORD(fi->dwFileVersionMS), LOWORD(fi->dwFileVersionMS), HIWORD(fi->dwFileVersionLS)
809  // HIWORD(fi->dwFileVersionLS), LOWORD(fi->dwFileVersionLS)
810  );
811  }
812  }
813 
814  delete[]pBuffer;
815  }
816 
817  return L" v" + strVersion;
818 }
819 
820 // ---------------------------------------------------------------------------
821 // Track Build Interface
822 // ---------------------------------------------------------------------------
823 void __fastcall TInterface::BuildTrackMenuItemClick(TObject *Sender) // Mode Menu Item
824 {
825  try
826  {
827  TrainController->LogEvent("BuildTrackMenuItemClick");
828  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BuildTrackMenuItemClick");
830  SetLevel1Mode(0);
831  Utilities->CallLogPop(1159);
832  }
833  catch(const Exception &e)
834  {
835  ErrorLog(120, e.Message);
836  }
837 }
838 // ---------------------------------------------------------------------------
839 
840 void __fastcall TInterface::AddTrackButtonClick(TObject *Sender)
841 {
842  try
843  {
844  TrainController->LogEvent("AddTrackButtonClick");
845  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTrackButtonClick");
847  SetLevel1Mode(38);
850  Utilities->CallLogPop(1162);
851  }
852  catch(const Exception &e)
853  {
854  ErrorLog(121, e.Message);
855  }
856 }
857 
858 // ---------------------------------------------------------------------------
859 void __fastcall TInterface::SpeedButtonClick(TObject *Sender)
860 {
861  try
862  {
863  TrainController->LogEvent("SpeedButtonClick");
864  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedButtonClick");
865  if(((TSpeedButton*)Sender)->Down)
866  {
867  CurrentSpeedButton = (TSpeedButton*)Sender;
868 // TrainController->LogEvent("SpeedButtonClick, " + CurrentSpeedButton->Tag); //v 1.3.1 - using non-AnsiString CurrentSpeedButton->Tag sends (for an unknown reason) a completely wrong string to LogEvent, usually "...(behind this message)"
869  TrainController->LogEvent("SpeedButtonClick, " + AnsiString(CurrentSpeedButton->Tag)); // new version //use for v1.3.2
870  }
871  else
872  CurrentSpeedButton = 0;
873  SelectionValid = false;
874  ReselectMenuItem->Enabled = false;
875  Utilities->CallLogPop(1163);
876  }
877  catch(const Exception &e)
878  {
879  ErrorLog(122, e.Message);
880  }
881 }
882 
883 // ---------------------------------------------------------------------------
884 void __fastcall TInterface::TrackOKButtonClick(TObject *Sender)
885 {
886  try
887  {
888  TrainController->LogEvent("TrackOKButtonClick");
889  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackOKButtonClick");
890  SelectionValid = false;
892  bool LocError;
893  int HLoc, VLoc;
894  // erase any corrupted PrefDirs then rebuild track & PrefDir vectors
895 // EveryPrefDir->EraseCorruptedElementsAfterTrackBuild(); not needed after dispensed with blank track elements for erased elements
896  if(!(Track->TryToConnectTrack(0, LocError, HLoc, VLoc, true))) // true for give messages
897  // if successful repositions TrackVector & builds TrackMap
898  {
899  if(LocError) // links not complete or other error - show offending element
900  {
901  while((Display->DisplayOffsetH - HLoc) > 0)
902  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
903  while((HLoc - Display->DisplayOffsetH) > (Utilities->ScreenElementWidth - 1))
905  while((Display->DisplayOffsetV - VLoc) > 0)
906  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
907  while((VLoc - Display->DisplayOffsetV) > (Utilities->ScreenElementHeight - 1))
910  Display->InvertElement(0, HLoc * 16, VLoc * 16);
911  ShowMessage("Incomplete track or other error - see inverted element (may be behind this message)");
912  ClearandRebuildRailway(1); // to clear inversion
914  SetLevel1Mode(39);
915  Level2TrackMode = AddTrack; // go to add track regardless of where started from
917  Utilities->CallLogPop(0);
918  return;
919  }
920  else
921  { // reach here if there are no track elements
922  ShowMessage("Unable to set any track links");
924  SetLevel1Mode(40);
926  SetLevel2TrackMode(4); // go to add track regardless of where started from
927  Utilities->CallLogPop(1);
928  return;
929  }
930  }
931  else
932  {
933  // success ('TrackFinished' set in TryToConnectTrack)
934  EveryPrefDir->RebuildPrefDirVector(0); // from TrackMap
935  ShowMessage("Successful Completion");
936  }
937 // success if reach here ('TrackFinished' set in TryToConnectTrack)
939  {
941  SetLevel1Mode(41);
943  }
944  else
945  {
947  SetLevel1Mode(36); // back to TrackMode if not in AddTrack mode
948  }
949  Utilities->CallLogPop(2);
950  }
951  catch(const Exception &e)
952  {
953  ErrorLog(3, e.Message);
954  }
955 }
956 
957 // ---------------------------------------------------------------------------
958 void __fastcall TInterface::SetGapsButtonClick(TObject *Sender)
959 {
960  try
961  {
962  TrainController->LogEvent("SetGapsButtonClick");
963  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetGapsButtonClick");
964  SelectionValid = false;
965  ReselectMenuItem->Enabled = false;
967  SetLevel1Mode(42);
970  Utilities->CallLogPop(1164);
971  }
972  catch(const Exception &e)
973  {
974  ErrorLog(123, e.Message);
975  }
976 }
977 
978 // ---------------------------------------------------------------------------
979 void __fastcall TInterface::AddTextButtonClick(TObject *Sender)
980 {
981  try
982  {
983  TrainController->LogEvent("AddTextButtonClick");
984  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddTextButtonClick");
986  SetLevel1Mode(43);
989  Utilities->CallLogPop(1165);
990  }
991  catch(const Exception &e)
992  {
993  ErrorLog(124, e.Message);
994  }
995 }
996 
997 // ---------------------------------------------------------------------------
998 void __fastcall TInterface::MoveTextOrGraphicButtonClick(TObject *Sender)
999 {
1000  try
1001  {
1002  TrainController->LogEvent("MoveTextOrGraphicButtonClick");
1003  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTextOrGraphicButtonClick");
1005  SetLevel1Mode(44);
1007  SetLevel2TrackMode(8);
1008  Utilities->CallLogPop(1166);
1009  }
1010  catch(const Exception &e)
1011  {
1012  ErrorLog(125, e.Message);
1013  }
1014 }
1015 
1016 // ---------------------------------------------------------------------------
1017 void __fastcall TInterface::TextBoxKeyPress(TObject *Sender, char &Key)
1018 {
1019  try
1020  {
1021  TrainController->LogEvent("TextBoxKeyPress," + AnsiString(Key));
1022  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextBoxKeyPress," + AnsiString(Key));
1023  if(Key == '\x0D') // CR
1024  {
1025  if(TextBox->Text != "") // if blank then don't save
1026  {
1027  if(Display->GetFont()->Color == clB5G5R5) // white
1028  {
1029  TFont *TempFont = new TFont;
1030  TempFont->Assign(Display->GetFont());
1031  TempFont->Color = clB0G0R0; // change to black for vector & saving
1032  Display->SetFont(TempFont);
1033  delete TempFont;
1034  }
1035  TFont *DisplayFont = Display->GetFont();
1036  TTextItem TempText = TTextItem(Text_X, Text_Y, TextBox->Text, DisplayFont);
1037  TempText.Font = DisplayFont; // may have been changed in above constructor when returned as reference
1039  }
1040  EditMenu->Enabled = true;
1041  TextBox->Visible = false;
1042  SetLevel2TrackMode(56); // to enable 'move text' if first text item added
1043  }
1044  else if(Key == '\x1B') // escape
1045  {
1046  TextBox->Visible = false;
1047  }
1048  Utilities->CallLogPop(3);
1049  }
1050  catch(const Exception &e)
1051  {
1052  ErrorLog(4, e.Message);
1053  }
1054 }
1055 
1056 // ---------------------------------------------------------------------------
1057 void __fastcall TInterface::LocationNameButtonClick(TObject *Sender)
1058 {
1059  try
1060  {
1061  TrainController->LogEvent("LocationNameButtonClick");
1062  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameButtonClick");
1064  SetLevel1Mode(45);
1066  SetLevel2TrackMode(9);
1067  Utilities->CallLogPop(1167);
1068  }
1069  catch(const Exception &e)
1070  {
1071  ErrorLog(126, e.Message);
1072  }
1073 }
1074 
1075 // ---------------------------------------------------------------------------
1076 void __fastcall TInterface::LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
1077 {
1078  try
1079  {
1080  TrainController->LogEvent("LocationNameKeyUp," + AnsiString(Key));
1081  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameKeyUp," + AnsiString(Key));
1082  if(Track->LNPendingList.empty())
1083  {
1084  ShowMessage("Error, location name being entered without an entry in LNPendingList");
1086  SetLevel1Mode(46);
1088  SetLevel2TrackMode(10);
1089  Utilities->CallLogPop(4);
1090  return;
1091  }
1092  if(Key == '\x1B') // escape
1093  {
1094  Track->LNPendingList.clear(); // get rid of existing entry
1096  SetLevel1Mode(47);
1098  SetLevel2TrackMode(11);
1099  Utilities->CallLogPop(5);
1100  return;
1101  }
1102  if(Key == '\x0D')
1103  {
1104  Screen->Cursor = TCursor(-11); // Hourglass;
1106  AnsiString ExistingName;
1107  if(Track->LNPendingList.front() > -1)
1108  ExistingName = Track->InactiveTrackElementAt(27, Track->LNPendingList.front()).LocationName;
1109  else
1110  ExistingName = Track->TrackElementAt(425, -1 - (Track->LNPendingList.front())).LocationName;
1111  if(Track->LocationNameAllocated(1, LocationNameTextBox->Text) && (ExistingName != LocationNameTextBox->Text))
1112  { // name allocated to a different location
1113  UnicodeString MessageStr = UnicodeString("Another location named '") + LocationNameTextBox->Text +
1114  UnicodeString("' already exists. If you continue its name will be erased. Do you wish to continue?");
1115  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
1116  if(button == IDNO)
1117  {
1118  Track->LNPendingList.clear(); // get rid of existing entry
1119  Screen->Cursor = TCursor(-2); // Arrow
1121  SetLevel1Mode(48);
1123  SetLevel2TrackMode(12);
1124  Utilities->CallLogPop(6);
1125  return;
1126  }
1128  Track->EnterLocationName(1, LocationNameTextBox->Text, false);
1129  int HPos, VPos;
1130  bool UseExistingPosition = false;
1131  if(EraseLocationNameText(0, LocationNameTextBox->Text, HPos, VPos))
1132  {;
1133  } // condition not used
1134  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1135  // but, the location to be named may also have an existing name, in which case that needs to be erased
1136  // and the position re-used
1137  if(ExistingName != "")
1138  {
1139  if(EraseLocationNameText(3, ExistingName, HPos, VPos))
1140  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1141  }
1142  AddLocationNameText(0, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1143  Screen->Cursor = TCursor(-2); // Arrow
1145  SetLevel1Mode(49);
1147  SetLevel2TrackMode(13);
1148  Utilities->CallLogPop(7);
1149  return;
1150  }
1151  else if(Track->LocationNameAllocated(2, LocationNameTextBox->Text) && (ExistingName == LocationNameTextBox->Text))
1152  { // same name being entered again
1153  Track->LNPendingList.clear(); // get rid of existing entry as the location already has this name
1154  // but in case the name is not already in text vector erase it and re-add it
1155  // if it wasn't in the vector erasing it has no effect
1156  int HPos, VPos;
1157  bool UseExistingPosition = false;
1158  if(EraseLocationNameText(2, LocationNameTextBox->Text, HPos, VPos))
1159  UseExistingPosition = true;
1160  // above may be redundant at v1.1.0 due to name erase in EnterLocationName
1161  AddLocationNameText(2, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1162  Screen->Cursor = TCursor(-2); // Arrow
1164  SetLevel1Mode(50);
1166  SetLevel2TrackMode(14);
1167  Utilities->CallLogPop(8);
1168  return;
1169  }
1170  else
1171  { // either a new name for an unnamed location, or a different name for a named location
1172  // check validity of entry
1173  AnsiString LocStr = LocationNameTextBox->Text;
1174  LocStr = LocStr.Trim(); // strip leading & trailing spaces, and control characters
1175  LocationNameTextBox->Text = LocStr; // reset this as used below
1176 /* drop this, now covered by ...Trim() above
1177  //strip leading spaces
1178  while((LocStr != "") && (LocStr[1] == ' '))
1179  {
1180  LocStr = LocStr.SubString(2, LocStr.Length()-1);
1181  }
1182 */
1183  if((LocStr != "") && (LocStr[1] >= '0') && (LocStr[1] <= '9')) // can't begin with a number
1184  {
1185  Screen->Cursor = TCursor(-2); // Arrow
1186  ShowMessage("Location name can't begin with a number");
1188  SetLevel1Mode(51);
1190  SetLevel2TrackMode(15);
1191  Utilities->CallLogPop(776);
1192  return;
1193  }
1194  if(LocStr.Length() > 50)
1195  {
1196  Screen->Cursor = TCursor(-2); // Arrow
1197  ShowMessage("Location name too long, 50 characters maximum");
1199  SetLevel1Mode(122);
1201  SetLevel2TrackMode(55);
1202  Utilities->CallLogPop(1735);
1203  return;
1204  }
1205  for(int x = 1; x <= LocStr.Length(); x++)
1206  {
1207  char Ch = LocStr[x];
1208  if((Ch != ' ') && (Ch != '&') && (Ch != '(') && (Ch != ')') && (Ch != ':') && (Ch != 39) && (Ch != '.') && (Ch != '-') && (Ch != '+') &&
1209  (Ch != '/') && ((Ch < '0') || (Ch > '9')) && ((Ch < 'A') || (Ch > 'Z')) && ((Ch < 'a') || (Ch > 'z')))
1210  {
1211  Screen->Cursor = TCursor(-2); // Arrow
1212  ShowMessage(
1213  "Location name contains one or more invalid characters, must be alphanumeric, brackets, space, full stop, colon, inverted comma, '-', '+', '/' or '&&'");
1215  SetLevel1Mode(52);
1217  SetLevel2TrackMode(16);
1218  Utilities->CallLogPop(777);
1219  return;
1220  }
1221  }
1222  if(LocStr == "cdt") // this has Time:Command which could be confused with Time:Loc
1223  {
1224  Screen->Cursor = TCursor(-2); // Arrow
1225  ShowMessage("Location name cannot be 'cdt', this name would interfere with the timetable");
1227  SetLevel1Mode(53);
1229  SetLevel2TrackMode(17);
1230  Utilities->CallLogPop(778);
1231  return;
1232  }
1233  Track->EnterLocationName(2, LocStr, false);
1234  // need to check if the location already has a name, and if so erase it from the textvector
1235  int HPos, VPos;
1236  bool UseExistingPosition = false;
1237  if(ExistingName != "")
1238  {
1239  if(EraseLocationNameText(1, ExistingName, HPos, VPos))
1240  UseExistingPosition = true; // may be redundant at v1.1.0 due to name erase in EnterLocationName
1241  }
1242  AddLocationNameText(1, LocationNameTextBox->Text, HPos, VPos, UseExistingPosition);
1243  Screen->Cursor = TCursor(-2); // Arrow
1245  SetLevel1Mode(54);
1247  SetLevel2TrackMode(18);
1248  Utilities->CallLogPop(9);
1249  return;
1250  }
1251  }
1252  Screen->Cursor = TCursor(-2); // Arrow
1253  Utilities->CallLogPop(10);
1254  }
1255  catch(const Exception &e)
1256  {
1257  ErrorLog(5, e.Message);
1258  }
1259 }
1260 
1261 // ---------------------------------------------------------------------------
1262 void __fastcall TInterface::SetLengthsButtonClick(TObject *Sender)
1263 {
1264  try
1265  {
1266  TrainController->LogEvent("SetLengthsButtonClick");
1267  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SetLengthsButtonClick");
1268  SelectLengthsFlag = false;
1269  ConstructPrefDir->ExternalClearPrefDirAnd4MultiMap(); // added for extended distances
1271  SetLevel1Mode(55);
1273  SetLevel2TrackMode(19);
1274  Utilities->CallLogPop(1168);
1275  }
1276  catch(const Exception &e)
1277  {
1278  ErrorLog(127, e.Message);
1279  }
1280 }
1281 
1282 // ---------------------------------------------------------------------------
1283 void __fastcall TInterface::LengthOKButtonClick(TObject *Sender)
1284 {
1285  try
1286  {
1287  TrainController->LogEvent("LengthOKButtonClick," + DistanceBox->Text + "," + SpeedLimitBox->Text);
1288  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthOKButtonClick");
1289  int Dist = 0, SpeedLimit = 0;
1290  AnsiString DistanceStr = DistanceBox->Text;
1291  if(SelectLengthsFlag && (DistanceStr == ""))
1292  DistanceStr = "No change";
1293  AnsiString SpeedStr = SpeedLimitBox->Text;
1294  if(SelectLengthsFlag && (SpeedStr == ""))
1295  SpeedStr = "No change";
1296  if(SelectLengthsFlag)
1297  {
1298  if(DistanceStr == "No change")
1299  Dist = -1; // i.e.don't change
1300  if(SpeedStr == "No change")
1301  SpeedLimit = -1; // i.e.don't change
1302  }
1303  else
1304  {
1305  if(DistanceStr == AnsiString(OverallDistance))
1306  Dist = -1; // i.e.don't change
1307  if((SpeedStr == "Mixed") || (SpeedStr == AnsiString(OverallSpeedLimit)))
1308  SpeedLimit = -1; // i.e.don't change
1309  }
1310  if(((Dist != -1) && (DistanceStr.Length() > 6)) || ((SpeedLimit != -1) && (SpeedStr.Length() > 6)))
1311  {
1312  ShowMessage("One or more entries too long");
1313  Utilities->CallLogPop(11);
1314  return;
1315  }
1316  if((DistanceStr == "") || (SpeedStr == ""))
1317  {
1318  ShowMessage("One or more entries blank");
1319  Utilities->CallLogPop(12);
1320  return;
1321  }
1322  if(SelectLengthsFlag && (Dist != -1))
1323  {
1324  for(int x = 1; x <= DistanceStr.Length(); x++)
1325  {
1326  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1327  {
1328  ShowMessage("Track length value must be a positive whole number, or blank for no change");
1329  Utilities->CallLogPop(1415);
1330  return;
1331  }
1332  }
1333  }
1334  if(!SelectLengthsFlag)
1335  {
1336  for(int x = 1; x <= DistanceStr.Length(); x++)
1337  {
1338  if((DistanceStr[x] < '0') || (DistanceStr[x] > '9'))
1339  {
1340  ShowMessage("Distance must be a positive whole number");
1341  Utilities->CallLogPop(13);
1342  return;
1343  }
1344  }
1345  }
1346  if(SelectLengthsFlag && (SpeedLimit != -1))
1347  {
1348  for(int x = 1; x <= SpeedStr.Length(); x++)
1349  {
1350  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1351  {
1352  ShowMessage("Speed limit must be a positive whole number, or blank for no change");
1353  Utilities->CallLogPop(1416);
1354  return;
1355  }
1356  }
1357  }
1358  if(!SelectLengthsFlag && (SpeedStr != "Mixed"))
1359  {
1360  for(int x = 1; x <= SpeedStr.Length(); x++)
1361  {
1362  if((SpeedStr[x] < '0') || (SpeedStr[x] > '9'))
1363  {
1364  ShowMessage("Speed limit must be a positive whole number, or 'Mixed'");
1365  Utilities->CallLogPop(14);
1366  return;
1367  }
1368  }
1369  }
1370  if(Dist != -1)
1371  Dist = DistanceStr.ToInt();
1372  if(SpeedLimit != -1)
1373  SpeedLimit = SpeedStr.ToInt();
1374 /* don't need this with new condition below
1375  if(SelectLengthsFlag && (Dist != -1) && (Dist < 20))
1376  {
1377  ShowMessage("Track length value must be a minimum of 20m, setting to 20m");
1378  Dist = 20;
1379  }
1380 */
1381  if(((Dist != -1) && (Dist < 20)) || ((SpeedLimit != -1) && (SpeedLimit < 10)) || ((SpeedLimit != -1) && (SpeedLimit > TTrain::MaximumSpeedLimit)))
1382  // new limiting values for v0.6 (used only to fail at either value 0); added TTrain::MaxSpeedLimit at v2.1.0
1383  {
1384  ShowMessage("Lengths must be 20m or more, and speeds must be between 10km/h and 400km/h"); // changed at v2.1.0 to limit max speed
1385  Utilities->CallLogPop(15);
1386  return;
1387  }
1388  DistanceBox->Text = "";
1389  SpeedLimitBox->Text = "";
1390  if(SelectLengthsFlag)
1391  {
1392  int LowSelectHLoc = SelectBitmapHLoc;
1393  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1394  int LowSelectVLoc = SelectBitmapVLoc;
1395  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1396  bool FoundFlag;
1397  bool NamedLocPresent = false;
1398  if((Dist != -1) && (Dist != DefaultTrackLength))
1399  {
1400  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1401  {
1402  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1403  {
1405  NamedLocPresent = true;
1406  }
1407  }
1408  }
1409  if(NamedLocPresent && (Dist < 50)) // changed in v2.4.0
1410  {
1411  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might depart too far from reality.");
1412  }
1413 
1414  if(NamedLocPresent && (Dist > 200)) // changed in v2.4.0
1415  {
1416  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might depart too far from reality.");
1417  }
1418 
1419  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1420  {
1421  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1422  {
1423  int VecPos = Track->GetVectorPositionFromTrackMap(34, x, y, FoundFlag);
1424  if(FoundFlag)
1425  {
1426  if(Dist > -1) // && !(Track->IsPlatformOrNamedNonStationLocationPresent(7, x, y)))
1427  {
1428  Track->TrackElementAt(692, VecPos).Length01 = Dist;
1429  if(Track->TrackElementAt(693, VecPos).Length23 != -1)
1430  {
1431  Track->TrackElementAt(694, VecPos).Length23 = Dist;
1432  }
1433  }
1434  if(SpeedLimit > -1)
1435  {
1436  Track->TrackElementAt(695, VecPos).SpeedLimit01 = SpeedLimit;
1437  if(Track->TrackElementAt(696, VecPos).SpeedLimit23 != -1)
1438  {
1439  Track->TrackElementAt(697, VecPos).SpeedLimit23 = SpeedLimit;
1440  }
1441  }
1442  }
1443  }
1444  }
1445  TrackLengthPanel->Visible = false;
1446  SelectLengthsFlag = false; // go back to normal distance setting mode
1447  }
1448  else
1449  {
1450  SetTrackLengths(1, Dist, SpeedLimit);
1451  }
1453  SetLevel1Mode(57);
1455  SetLevel2TrackMode(21);
1456  Utilities->CallLogPop(16);
1457  }
1458  catch(const Exception &e)
1459  {
1460  ErrorLog(6, e.Message);
1461  }
1462 }
1463 
1464 // ---------------------------------------------------------------------------
1465 void __fastcall TInterface::LengthCancelButtonClick(TObject *Sender)
1466 {
1467  try
1468  {
1469  TrainController->LogEvent("LengthCancelButtonClick");
1470  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthCancelButtonClick");
1471  DistanceBox->Text = "";
1472  SpeedLimitBox->Text = "";
1473  TrackLengthPanel->Visible = false;
1474  SelectLengthsFlag = false; // go back to normal distance setting mode
1476  SetLevel1Mode(59);
1478  SetLevel2TrackMode(23);
1479  Utilities->CallLogPop(1169);
1480  }
1481  catch(const Exception &e)
1482  {
1483  ErrorLog(128, e.Message);
1484  }
1485 }
1486 
1487 // ---------------------------------------------------------------------------
1488 void __fastcall TInterface::ResetDefaultLengthButtonClick(TObject *Sender)
1489 {
1490  try
1491  {
1492  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ResetDefaultLengthButtonClick");
1493  TMsgDlgButtons Buttons;
1494  Buttons << mbYes << mbNo;
1495  if(MessageDlg("This will reset the selected elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1496  {
1497  // leave all as was before
1498  Utilities->CallLogPop(17);
1499  return;
1500  }
1501  else
1502  {
1503  TrainController->LogEvent("Accepted ResetDefaultLengthButtonClick");
1504  DistanceBox->Text = "";
1505  SpeedLimitBox->Text = "";
1506  if(SelectLengthsFlag)
1507  {
1508  int LowSelectHLoc = SelectBitmapHLoc;
1509  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
1510  int LowSelectVLoc = SelectBitmapVLoc;
1511  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
1512  bool FoundFlag;
1513  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
1514  {
1515  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
1516  {
1517  int VecPos = Track->GetVectorPositionFromTrackMap(35, x, y, FoundFlag);
1518  if(FoundFlag)
1519  {
1521  if(Track->TrackElementAt(699, VecPos).Length23 != -1)
1522  {
1524  }
1526  if(Track->TrackElementAt(702, VecPos).SpeedLimit23 != -1)
1527  {
1529  }
1530  }
1531  }
1532  }
1533  TrackLengthPanel->Visible = false;
1534 // ClearandRebuildRailway(47); don't need this
1535  SelectLengthsFlag = false; // go back to normal distance setting mode
1536  }
1537  else
1538  {
1539  TrackLengthPanel->Visible = false;
1540  bool FoundFlag;
1541  if(ConstructPrefDir->PrefDirSize() == 0)
1542  {
1543  Utilities->CallLogPop(1120);
1544  return;
1545  }
1546  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
1547  {
1548  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(169, x);
1549  TTrackElement & TrackElement = Track->TrackElementAt(37, Track->GetVectorPositionFromTrackMap(40, PrefDirElement.HLoc, PrefDirElement.VLoc,
1550  FoundFlag));
1551  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover) || (TrackElement.TrackType == Bridge))
1552  // only set the relevant track to default length & speed limit
1553  {
1554  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be one of each for points
1555  {
1556  TrackElement.Length01 = DefaultTrackLength;
1557  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1558  }
1559  else
1560  {
1561  TrackElement.Length23 = DefaultTrackLength;
1562  TrackElement.SpeedLimit23 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1563  }
1564  }
1565  else // any other 1 track element, including platforms being present
1566  {
1567  if((PrefDirElement.GetELinkPos() > 1) && (PrefDirElement.GetXLinkPos() > 1))
1568  {
1569  throw Exception("Error, XLinkPos > 1 in SetOneDefaultTrackLength at " + AnsiString(TrackElement.HLoc) + " & " +
1570  AnsiString(TrackElement.VLoc));
1571  }
1572  TrackElement.Length01 = DefaultTrackLength;
1573  TrackElement.SpeedLimit01 = DefaultTrackSpeedLimit; // 200km/h = 125mph
1574  TrackElement.Length23 = -1;
1575  TrackElement.SpeedLimit23 = -1;
1576  }
1577  }
1578  }
1580  SetLevel1Mode(61);
1582  SetLevel2TrackMode(25);
1583  }
1584  Utilities->CallLogPop(18);
1585  }
1586  catch(const Exception &e)
1587  {
1588  ErrorLog(7, e.Message);
1589  }
1590 }
1591 
1592 // ---------------------------------------------------------------------------
1593 void __fastcall TInterface::RestoreAllDefaultLengthsButtonClick(TObject *Sender)
1594 {
1595  try
1596  {
1597  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreAllDefaultLengthsButtonClick");
1598  TMsgDlgButtons Buttons;
1599  Buttons << mbYes << mbNo;
1600  if(MessageDlg("This will reset ALL track elements to default lengths & speed limits. Proceed?", mtWarning, Buttons, 0) == mrNo)
1601  {
1602  // leave all as was before
1603  Utilities->CallLogPop(19);
1604  return;
1605  }
1606  else
1607  {
1609  }
1610  TrainController->LogEvent("Accepted RestoreAllDefaultLengthsButtonClick");
1611  DistanceBox->Text = "";
1612  SpeedLimitBox->Text = "";
1613  TrackLengthPanel->Visible = false;
1614  SelectLengthsFlag = false; // go back to normal distance setting mode
1616  SetLevel1Mode(63);
1618  SetLevel2TrackMode(27);
1619  Utilities->CallLogPop(20);
1620  }
1621  catch(const Exception &e)
1622  {
1623  ErrorLog(8, e.Message);
1624  }
1625 }
1626 
1627 // ---------------------------------------------------------------------------
1628 void __fastcall TInterface::ExitTrackButtonClick(TObject *Sender)
1629 {
1630  try
1631  {
1632  TrainController->LogEvent("ExitTrackButtonClick");
1633  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTrackButtonClick");
1634  if(Level2TrackMode == CutMoving)
1635  {
1636  Level2TrackMode = Pasting; // to paste the selection
1637  SetLevel2TrackMode(53);
1638  }
1639  DevelopmentPanel->Visible = false; // development use only
1640  ScreenGridFlag = false;
1641  SelectionValid = false;
1642  Track->SelectGraphicVector.clear();
1643  // delete all unwanted TPictures in UserGraphicMap
1644  if(!Track->UserGraphicMap.empty()) // if empty skip it
1645  {
1646  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1647  do
1648  {
1649  bool GraphicFoundInVector = false;
1650  for(TTrack::TUserGraphicVector::iterator UGVIt = Track->UserGraphicVector.begin(); UGVIt < Track->UserGraphicVector.end(); UGVIt++)
1651  {
1652  if(UGMIt->first == UGVIt->FileName)
1653  {
1654  GraphicFoundInVector = true;
1655  break;
1656  }
1657  }
1658  if(!GraphicFoundInVector)
1659  {
1660  delete UGMIt->second;
1661  Track->UserGraphicMap.erase(UGMIt);
1662  UGMIt = Track->UserGraphicMap.begin(); // reset the iterator because erasing an element it points to invalidates it & if use it after then
1663  // behaviour is undefined, the iteration will end eventually because the map has got shorter after an erase
1664  }
1665  else
1666  {
1667  UGMIt++;
1668  }
1669  }
1670  while(UGMIt != Track->UserGraphicMap.end());
1671  }
1672  Level1Mode = BaseMode;
1673  SetLevel1Mode(2);
1674  Utilities->CallLogPop(1170);
1675  }
1676  catch(const Exception &e)
1677  {
1678  ErrorLog(129, e.Message);
1679  }
1680 }
1681 
1682 // ---------------------------------------------------------------------------
1683 void __fastcall TInterface::TextOrUserGraphicGridButtonClick(TObject *Sender)
1684 {
1685  try
1686  {
1687  TrainController->LogEvent("TextOrUserGraphicGridButtonClick," + AnsiString(TextOrUserGraphicGridVal));
1688  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TextOrUserGraphicGridButtonClick");
1689  if(TextOrUserGraphicGridVal == 1)
1690  {
1692  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision2");
1693  }
1694  else if(TextOrUserGraphicGridVal == 2)
1695  {
1697  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision4");
1698  }
1699  else if(TextOrUserGraphicGridVal == 4)
1700  {
1702  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision8");
1703  }
1704  else if(TextOrUserGraphicGridVal == 8)
1705  {
1707  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision16");
1708  }
1709  else
1710  {
1712  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
1713  }
1714  Utilities->CallLogPop(1171);
1715  }
1716  catch(const Exception &e)
1717  {
1718  ErrorLog(130, e.Message);
1719  }
1720 }
1721 
1722 // ---------------------------------------------------------------------------
1723 void __fastcall TInterface::SigAspectButtonClick(TObject *Sender)
1724 {
1725  try
1726  {
1727  TrainController->LogEvent("SigAspectButtonClick," + AnsiString(Track->SignalAspectBuildMode));
1728  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigAspectButtonClick");
1730  {
1732  SigAspectButton->Glyph->LoadFromResourceName(0, "ThreeAspect");
1733  }
1735  {
1737  SigAspectButton->Glyph->LoadFromResourceName(0, "TwoAspect");
1738  }
1740  {
1742  SigAspectButton->Glyph->LoadFromResourceName(0, "GroundSig");
1743 // set all signal glyphs to ground signals
1745  }
1746  else
1747  {
1749  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
1750 // set all signal glyphs to normal signals
1752  }
1753  Utilities->CallLogPop(1869);
1754  }
1755  catch(const Exception &e)
1756  {
1757  ErrorLog(180, e.Message);
1758  }
1759 }
1760 
1761 // ---------------------------------------------------------------------------
1762 void __fastcall TInterface::FontButtonClick(TObject *Sender)
1763 {
1764  try
1765  {
1766  TrainController->LogEvent("FontButtonClick");
1767  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FontButtonClick");
1768  FontDialog->Font = Display->GetFont(); //sets the dialog box font to the currently used font
1769  FontDialog->Execute(); //this displays the dialog box
1770  if(FontDialog->Font->Color == clB5G5R5) //white
1771  FontDialog->Font->Color = clB0G0R0; //black - don't store white in font, will display black as white on dark backgrounds
1772  Display->SetFont(FontDialog->Font); //sets the displayed font to the output from the dialog box
1773  if(TextBox->Visible)
1774  TextBox->SetFocus();
1775  else if(LocationNameTextBox->Visible)
1776  LocationNameTextBox->SetFocus();
1777  Utilities->CallLogPop(1172);
1778  }
1779  catch(const Exception &e)
1780  {
1781  ErrorLog(131, e.Message);
1782  }
1783 }
1784 
1785 // ---------------------------------------------------------------------------
1786 
1787 void __fastcall TInterface::ScreenGridButtonClick(TObject *Sender)
1788 {
1789  try
1790  {
1791  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenGridButtonClick");
1792  if(ScreenGridFlag)
1793  {
1794  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid off");
1795  ScreenGridFlag = false;
1796  }
1797  else
1798  {
1799  TrainController->LogEvent("ScreenGridButtonClick + ScreenGrid on");
1800  ScreenGridFlag = true;
1801  }
1803  Utilities->CallLogPop(89);
1804  }
1805  catch(const Exception &e)
1806  {
1807  ErrorLog(33, e.Message);
1808  }
1809 }
1810 
1811 // ---------------------------------------------------------------------------
1812 // PrefDir Interface
1813 // ---------------------------------------------------------------------------
1814 void __fastcall TInterface::PlanPrefDirsMenuItemClick(TObject *Sender) // Mode Menu Item
1815 {
1816  try
1817  {
1818  TrainController->LogEvent("PlanPrefDirsMenuItemClick");
1819  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PlanPrefDirsMenuItemClick");
1821  SetLevel1Mode(3);
1822  Utilities->CallLogPop(1173);
1823  }
1824  catch(const Exception &e)
1825  {
1826  ErrorLog(132, e.Message);
1827  }
1828 }
1829 
1830 // ---------------------------------------------------------------------------
1831 void __fastcall TInterface::AddPrefDirButtonClick(TObject *Sender)
1832 {
1833  try
1834  {
1835  TrainController->LogEvent("AddPrefDirButtonClick");
1836  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddPrefDirButtonClick");
1837  if(ConstructPrefDir->PrefDirSize() == 0)
1838  {
1839  ShowMessage("No preferred direction selection");
1840  Utilities->CallLogPop(22);
1841  return;
1842  }
1843  Screen->Cursor = TCursor(-11); // Hourglass;
1847  SetLevel1Mode(4);
1848  Screen->Cursor = TCursor(-2); // Arrow
1849  Utilities->CallLogPop(23);
1850  }
1851  catch(const Exception &e)
1852  {
1853  ErrorLog(10, e.Message);
1854  }
1855 }
1856 
1857 // ---------------------------------------------------------------------------
1858 void __fastcall TInterface::DeleteAllPrefDirButtonClick(TObject *Sender)
1859 {
1860  try
1861  {
1862  TrainController->LogEvent("DeleteAllPrefDirButtonClick");
1863  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteAllPrefDirButtonClick");
1864  TMsgDlgButtons Buttons;
1865  Buttons << mbYes << mbNo;
1866  if(MessageDlg("Do you really want to clear all preferred directions?", mtWarning, Buttons, 0) == mrNo)
1867  {
1868  Utilities->CallLogPop(24);
1869  return;
1870  }
1871  // leave all as was before pressed DeleteAllPrefDirButton
1872  else
1873  {
1878  SetLevel1Mode(5);
1879  }
1880  Utilities->CallLogPop(25);
1881  }
1882  catch(const Exception &e)
1883  {
1884  ErrorLog(11, e.Message);
1885  }
1886 }
1887 // ---------------------------------------------------------------------------
1888 
1889 void __fastcall TInterface::DeleteOnePrefDirButtonClick(TObject *Sender)
1890 {
1891  try
1892  {
1893  TrainController->LogEvent("DeleteOnePrefDirButtonClick");
1894  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteOnePrefDirButtonClick");
1895  ResetChangedFileDataAndCaption(18, false);
1896 // RlyFile = false; - don't alter this just for PrefDir changes
1897  Screen->Cursor = TCursor(-11); // Hourglass;
1898  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
1899  {
1902  }
1905  SetLevel1Mode(81); // all PrefDir truncated
1906  Screen->Cursor = TCursor(-2); // Arrow
1907  Utilities->CallLogPop(1591);
1908  }
1909  catch(const Exception &e)
1910  {
1911  ErrorLog(46, e.Message);
1912  }
1913 }
1914 
1915 // ---------------------------------------------------------------------------
1916 
1917 void __fastcall TInterface::ExitPrefDirButtonClick(TObject *Sender)
1918 {
1919  try
1920  {
1921  TrainController->LogEvent("ExitPrefDirButtonClick");
1922  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitPrefDirButtonClick");
1923  Level1Mode = BaseMode;
1924  SetLevel1Mode(6);
1925  Utilities->CallLogPop(1554);
1926  }
1927  catch(const Exception &e)
1928  {
1929  ErrorLog(133, e.Message);
1930  }
1931 }
1932 
1933 // ---------------------------------------------------------------------------
1934 // Operate Railway Interface
1935 // ---------------------------------------------------------------------------
1936 void __fastcall TInterface::OperateRailwayMenuItemClick(TObject *Sender) // Mode Menu Item
1937 {
1938  try
1939  {
1940  TrainController->LogEvent("OperateRailwayMenuItemClick");
1941  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateRailwayMenuItemClick");
1942  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
1943  AllRoutes->NextRouteID = 0; // reset to 0 whenever enter operating mode
1944  Level1Mode = OperMode;
1945  SetLevel1Mode(7);
1946  Utilities->CallLogPop(26);
1947  }
1948  catch(const Exception &e)
1949  {
1950  ErrorLog(12, e.Message);
1951  }
1952 }
1953 
1954 // ---------------------------------------------------------------------------
1955 void __fastcall TInterface::OperateButtonClick(TObject *Sender)
1956 {
1957  try
1958  {
1959  TrainController->LogEvent("StartOperationButtonClick");
1960  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperateButtonClick");
1962  {
1964  SetLevel2OperMode(0);
1965  }
1966  else
1967  {
1969  SetLevel2OperMode(1);
1970  }
1971  Utilities->CallLogPop(1175);
1972  }
1973  catch(const Exception &e)
1974  {
1975  ErrorLog(37, e.Message);
1976  }
1977 }
1978 
1979 // ---------------------------------------------------------------------------
1980 void __fastcall TInterface::AutoSigsButtonClick(TObject *Sender)
1981  // must have PrefDirs to be available
1982 {
1983  try
1984  {
1985  TrainController->LogEvent("AutoSigsButtonClick");
1986  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AutoSigsButtonClick");
1987  AutoSigsFlag = true;
1988  PreferredRoute = true;
1989  ConsecSignalsRoute = true;
1990 
1991  AutoSigsButton->Enabled = false;
1992  SigPrefButton->Enabled = true;
1993  UnrestrictedButton->Enabled = true;
1994 
1995  InfoPanel->Visible = true;
1996  if(Level2OperMode == PreStart)
1997  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
1998  else
1999  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
2000  InfoCaptionStore = InfoPanel->Caption;
2001  AutoRouteStartMarker->PlotOriginal(1, Display); // if overlay not plotted will ignore
2002  SigRouteStartMarker->PlotOriginal(2, Display); // if overlay not plotted will ignore
2003  NonSigRouteStartMarker->PlotOriginal(3, Display); // if overlay not plotted will ignore
2005  Utilities->CallLogPop(28);
2006  }
2007  catch(const Exception &e)
2008  {
2009  ErrorLog(14, e.Message);
2010  }
2011 }
2012 
2013 // ---------------------------------------------------------------------------
2014 void __fastcall TInterface::SigPrefButtonClick(TObject *Sender)
2015  // must have PrefDirs to be available
2016 {
2017  try
2018  {
2019  TrainController->LogEvent("SigPrefButtonClick");
2020  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SigPrefButtonClick");
2021  AutoSigsFlag = false;
2022  PreferredRoute = true;
2023  ConsecSignalsRoute = true;
2024 
2025  AutoSigsButton->Enabled = true;
2026  SigPrefButton->Enabled = false;
2027  UnrestrictedButton->Enabled = true;
2028 
2029  InfoPanel->Visible = true;
2030  if(Level2OperMode == PreStart)
2031  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
2032  else
2033  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
2034  InfoCaptionStore = InfoPanel->Caption;
2035  AutoRouteStartMarker->PlotOriginal(4, Display); // if overlay not plotted will ignore
2036  SigRouteStartMarker->PlotOriginal(5, Display); // if overlay not plotted will ignore
2037  NonSigRouteStartMarker->PlotOriginal(6, Display); // if overlay not plotted will ignore
2039  Utilities->CallLogPop(29);
2040  }
2041  catch(const Exception &e)
2042  {
2043  ErrorLog(15, e.Message);
2044  }
2045 }
2046 
2047 // ---------------------------------------------------------------------------
2048 void __fastcall TInterface::UnrestrictedButtonClick(TObject *Sender)
2049 {
2050  try
2051  {
2052  TrainController->LogEvent("NoSigNonPrefButtonClick");
2053  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NoSigNonPrefButtonClick");
2054  AutoSigsFlag = false;
2055  PreferredRoute = false;
2056  ConsecSignalsRoute = false;
2057  if(EveryPrefDir->PrefDirSize() > 0)
2058  {
2059  AutoSigsButton->Enabled = true;
2060  SigPrefButton->Enabled = true;
2061  UnrestrictedButton->Enabled = false;
2062  }
2063  else
2064  {
2065  AutoSigsButton->Enabled = false;
2066  SigPrefButton->Enabled = false;
2067  UnrestrictedButton->Enabled = false;
2068  }
2069  InfoPanel->Visible = true;
2070  if(Level2OperMode == PreStart)
2071  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2072  else
2073  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
2074  InfoCaptionStore = InfoPanel->Caption;
2075  AutoRouteStartMarker->PlotOriginal(7, Display); // if overlay not plotted will ignore
2076  SigRouteStartMarker->PlotOriginal(8, Display); // if overlay not plotted will ignore
2077  NonSigRouteStartMarker->PlotOriginal(9, Display); // if overlay not plotted will ignore
2079  Utilities->CallLogPop(30);
2080  }
2081  catch(const Exception &e)
2082  {
2083  ErrorLog(16, e.Message);
2084  }
2085 }
2086 
2087 // ---------------------------------------------------------------------------
2088 void __fastcall TInterface::RouteCancelButtonClick(TObject *Sender)
2089 {
2090  try
2091  {
2092  TrainController->LogEvent("RouteCancelButtonClick");
2093  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RouteCancelButtonClick");
2094  RouteCancelFlag = true;
2095  InfoPanel->Visible = true;
2096  InfoPanel->Caption = "ROUTE CANCELLING: Right click on truncate element, first element to cancel (anywhere else to skip)";
2097  RouteCancelButton->Enabled = false;
2098  AutoRouteStartMarker->PlotOriginal(32, Display); // if overlay not plotted will ignore
2099  SigRouteStartMarker->PlotOriginal(33, Display); // if overlay not plotted will ignore
2100  NonSigRouteStartMarker->PlotOriginal(34, Display); // if overlay not plotted will ignore
2101  Utilities->CallLogPop(1176);
2102  }
2103  catch(const Exception &e)
2104  {
2105  ErrorLog(35, e.Message);
2106  }
2107 }
2108 
2109 // ---------------------------------------------------------------------------
2110 void __fastcall TInterface::PerformanceLogButtonClick(TObject *Sender)
2111 {
2112  try
2113  {
2114  TrainController->LogEvent("PerformanceLogButtonClick");
2115  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformanceLogButtonClick");
2117  {
2118  ShowPerformancePanel = true;
2119  PerformancePanel->Visible = true;
2120  PerformanceLogButton->Glyph->LoadFromResourceName(0, "HideLog");
2121  }
2122  else
2123  {
2124  ShowPerformancePanel = false;
2125  PerformancePanel->Visible = false;
2126  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2127  }
2128  Utilities->CallLogPop(1177);
2129  }
2130  catch(const Exception &e)
2131  {
2132  ErrorLog(36, e.Message);
2133  }
2134 }
2135 // ---------------------------------------------------------------------------
2136 
2137 void __fastcall TInterface::ExitOperationButtonClick(TObject *Sender)
2138 {
2139  try
2140  {
2141  TrainController->LogEvent("ExitOperationButtonClick");
2142  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitOperationButtonClick");
2143 
2144  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
2145  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2147  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
2148  TrainController->BaseTime = TDateTime::CurrentDateTime();
2150  if(button == IDNO)
2151  {
2152  Utilities->CallLogPop(751);
2153  return;
2154  }
2155  Track->ResetSignals(1);
2156  Track->ResetPoints(1);
2157  TrainController->SendPerformanceSummary(0, Utilities->PerformanceFile); // must come before trains finished becuase examines the train vectors
2158  Utilities->PerformanceFile.close();
2161  RouteMode = None;
2162  PreferredRoute = true;
2163  ConsecSignalsRoute = true;
2165  ShowPerformancePanel = false;
2166  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
2167  ShowOperatorActionPanel = false; // new at v2.2.0
2168  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
2169  PerformanceLogBox->Lines->Clear();
2170  PerformancePanel->Visible = false;
2171  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
2172  PerformancePanel->Left = MainScreen->Left;
2173 // TipButton->Glyph->LoadFromResourceName(0, "ShowLog"); //'Trains in play' new at v2.2.0
2174  OAListBox->Clear();
2175  OperatorActionPanel->Visible = false;
2176  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height;
2177  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width; ;
2179  AllRoutes->LockedRouteVector.clear();
2180  Level1Mode = BaseMode;
2181  SetLevel1Mode(8); // calls Clearand...
2182  Utilities->CallLogPop(1555);
2183  }
2184  catch(const Exception &e)
2185  {
2186  ErrorLog(13, e.Message);
2187  }
2188 }
2189 
2190 // ---------------------------------------------------------------------------
2191 // Menu Interface (for items not already covered above)
2192 // ---------------------------------------------------------------------------
2193 void __fastcall TInterface::LoadRailwayMenuItemClick(TObject *Sender)
2194 {
2195  try
2196  {
2197  TrainController->LogEvent("LoadRailwayMenuItemClick");
2198  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadRailwayMenuItemClick");
2199  if(!ClearEverything(1))
2200  {
2201  Utilities->CallLogPop(1139);
2202  return;
2203  }
2204  // LoadRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly"; //as was
2205  // changed at v2.0.0 (Embarcadero change) to show all files together
2206  LoadRailwayDialog->Filter = "Railway files (*.rly or *.dev)|*.rly; *.dev";
2207  if(LoadRailwayDialog->Execute())
2208  {
2209  TrainController->LogEvent("LoadRailway " + AnsiString(LoadRailwayDialog->FileName));
2210  LoadRailway(0, AnsiString(LoadRailwayDialog->FileName));
2211  }
2212  // else ShowMessage("Load Aborted"); drop this
2213  // Display->Update(); //display updated in ClearandRebuildRailway
2214  Track->CalcHLocMinEtc(9);
2215  Level1Mode = BaseMode;
2218  SetLevel1Mode(11); // calls Clearand... to plot the new railway
2219  Utilities->CallLogPop(31);
2220  }
2221  catch(const Exception &e)
2222  {
2223  ErrorLog(17, e.Message);
2224  }
2225 }
2226 // ---------------------------------------------------------------------------
2227 
2228 void TInterface::LoadRailway(int Caller, AnsiString LoadFileName)
2229 { // display of the loaded railway covered in the calling routine
2230  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRailway," + LoadFileName);
2231  if(FileIntegrityCheck(0, LoadFileName.c_str()))
2232  {
2233  Screen->Cursor = TCursor(-11); // Hourglass;
2234  std::ifstream VecFile(LoadFileName.c_str());
2235  if(!(VecFile.fail()))
2236  {
2237  AnsiString TempString = Utilities->LoadFileString(VecFile); // version number
2238  int TempOffsetHHome = Utilities->LoadFileInt(VecFile);
2239  int TempOffsetVHome = Utilities->LoadFileInt(VecFile);
2240  bool GraphicsFollow = false;
2241  // can't load DisplayOffsetH & VHome until after LoadTrack as that calls TrackClear & zeroes them
2242 // load track elements
2243  Track->LoadTrack(1, VecFile, GraphicsFollow);
2244 // load text elements
2245  TextHandler->LoadText(0, VecFile);
2246 // load PrefDir elements
2247  EveryPrefDir->LoadPrefDir(0, VecFile);
2248  if(GraphicsFollow)
2249  {
2250 // load user graphics
2251  Track->LoadGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder
2252  }
2253  EveryPrefDir->CheckPrefDirAgainstTrackVector(0); // clears PrefDir if any discrepancies found
2254  VecFile.close();
2255  Display->DisplayOffsetHHome = TempOffsetHHome;
2256  Display->DisplayOffsetVHome = TempOffsetVHome;
2258 
2259  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
2260  TempFont->Style.Clear();
2261  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
2262  TempFont->Size = 10;
2263  TempFont->Color = clB0G0R0;
2264  TempFont->Charset = (TFontCharset)(0);
2265  MainScreen->Canvas->Font->Assign(TempFont);
2266  delete TempFont;
2267 
2268 // calculate starting zoomed out offset values - same as when zoom out button clicked
2269  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
2270 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
2271  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
2272  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
2273  if((LeftExcess > 0) && (RightExcess > 0))
2274  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
2275  else if((LeftExcess > 0) && (RightExcess <= 0))
2276  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
2277  (Utilities->ScreenElementWidth / 2); // normalise to nearest half screen
2278  else if((LeftExcess <= 0) && (RightExcess > 0))
2279  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
2280  else
2281  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
2282 
2283  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
2284  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
2285  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
2286  if((TopExcess > 0) && (BotExcess > 0))
2287  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
2288  else if((TopExcess > 0) && (BotExcess <= 0))
2289  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
2290  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
2291  else if((TopExcess <= 0) && (BotExcess > 0))
2292  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
2293  else
2294  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
2295 // all above same as when zoom out button clicked
2296  Display->DisplayZoomOutOffsetVHome = Display->DisplayZoomOutOffsetV; // now set zoomed out 'home' values
2298 
2299  SavedFileName = AnsiString(LoadRailwayDialog->FileName); // includes the full PrefDir
2300  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
2301  {
2302  char LastChar = SavedFileName[SavedFileName.Length()];
2303  if((LastChar == 'y') || (LastChar == 'Y'))
2304  {
2305  if(!(Track->IsReadyForOperation()))
2306  {
2307  ShowMessage("Railway not ready for operation so unable to load as a .rly file. Loading as a new railway under development");
2308  SavedFileName = "";
2309  RlyFile = false;
2310  RailwayTitle = "";
2311  TimetableTitle = "";
2312  SetCaption(5);
2313  Track->CalcHLocMinEtc(1);
2314  Screen->Cursor = TCursor(-2); // Arrow
2315  Level1Mode = BaseMode;
2316  SetLevel1Mode(9);
2317  Utilities->CallLogPop(1136);
2318  return;
2319  }
2320  else
2321  {
2322  RlyFile = true;
2323  }
2324  }
2325  else
2326  {
2327  RlyFile = false;
2328  }
2329  }
2330  else
2331  {
2332  RlyFile = false;
2333  }
2334  FileChangedFlag = false;
2335  for(int x = AnsiString(LoadRailwayDialog->FileName).Length(); x > 0; x--)
2336  {
2337  if(AnsiString(LoadRailwayDialog->FileName)[x] == '\\')
2338  {
2339  RailwayTitle = AnsiString(LoadRailwayDialog->FileName).SubString(x + 1, AnsiString(LoadRailwayDialog->FileName).Length() - x - 4);
2340  TimetableTitle = "";
2341  SetCaption(6);
2342  break;
2343  }
2344  }
2345  } // if(VecFile)
2346  else
2347  ShowMessage("File open failed prior to load");
2348  Screen->Cursor = TCursor(-2); // Arrow
2349  } // if(FileIntegrityCheck(LoadRailwayDialog->FileName.c_str()))
2350  else
2351  ShowMessage("File integrity check failed - unable to load");
2352  Utilities->CallLogPop(1774);
2353 }
2354 
2355 // ---------------------------------------------------------------------------
2356 
2357 void __fastcall TInterface::SaveMenuItemClick(TObject *Sender)
2358 {
2359 // save under existing name
2360 // no need to alter RlyFile for saving under existing name
2361 
2362  try
2363  {
2364  TrainController->LogEvent("SaveMenuItemClick, " + SavedFileName);
2365  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveMenuItemClick");
2366  Screen->Cursor = TCursor(-11); // Hourglass;
2367  std::ofstream VecFile(SavedFileName.c_str());
2368  if(!(VecFile.fail()))
2369  {
2373  // save track elements
2374  if(Track->UserGraphicVector.empty())
2375  {
2376  Track->SaveTrack(3, VecFile, false); // false for no graphics (**Active elements** saved as marker)
2377  }
2378  else
2379  {
2380  Track->SaveTrack(8, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
2381  }
2382  // save text elements
2383  TextHandler->SaveText(0, VecFile);
2384  // save PrefDir elements
2385  EveryPrefDir->SavePrefDirVector(0, VecFile);
2386  if(!Track->UserGraphicVector.empty())
2387  {
2388  // save user graphics
2389  Track->SaveUserGraphics(0, VecFile);
2390  }
2391  FileChangedFlag = false;
2392  VecFile.close();
2393  }
2394  else
2395  ShowMessage("File open failed prior to save");
2396  Screen->Cursor = TCursor(-2); // Arrow
2397  Level1Mode = BaseMode;
2398  SetLevel1Mode(12); // to disable the save option
2399  Utilities->CallLogPop(1178);
2400  }
2401  catch(const Exception &e)
2402  {
2403  ErrorLog(135, e.Message);
2404  }
2405 }
2406 
2407 // ---------------------------------------------------------------------------
2408 void __fastcall TInterface::SaveAsMenuItemClick(TObject *Sender)
2409 {
2410  try
2411  {
2412  TrainController->LogEvent("SaveAsMenuItemClick");
2413  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveAsMenuItemClick");
2414  SaveAsSubroutine(0);
2415  Utilities->CallLogPop(32);
2416  }
2417  catch(const Exception &e)
2418  {
2419  ErrorLog(18, e.Message);
2420  }
2421 }
2422 
2423 // ---------------------------------------------------------------------------
2424 
2425 void __fastcall TInterface::SaveImageNoGridMenuItemClick(TObject *Sender)
2426 { // need to stop clock in case invoke during operation
2427  try
2428  {
2429  TrainController->LogEvent("SaveImageNoGridMenuItemClick");
2430  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageNoGridMenuItemClick");
2431  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2432  {
2433  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2434  Utilities->CallLogPop(1695);
2435  return;
2436  }
2437  Screen->Cursor = TCursor(-11); // Hourglass;
2438  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2440  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2441  // format "16/06/2009 20:55:17"
2442  // avoid characters in filename:= / \ : * ? " < > |
2443  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2444  AnsiString ShortName = "";
2445  for(int x = ImageFileName.Length(); x > 0; x--)
2446  {
2447  if(ImageFileName[x] == '\\')
2448  {
2449  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2450  break;
2451  }
2452  }
2453  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2454  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2455  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2456 
2457  int HPosMin = Track->GetHLocMin() * 16;
2458  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2459  int VPosMin = Track->GetVLocMin() * 16;
2460  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2461  RailwayImage->Width = HPosMax - HPosMin;
2462  RailwayImage->Height = VPosMax - VPosMin;
2463 
2464  // need to check if there is any text that extends past HPosMax or below VPosMax
2465  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2466  if(!TextHandler->TextVector.empty())
2467  {
2468  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2469  {
2470  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2471  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2472  if(NewWidth > RailwayImage->Width)
2473  {
2474  RailwayImage->Width = NewWidth;
2475  }
2476  if(NewHeight > RailwayImage->Height)
2477  {
2478  RailwayImage->Height = NewHeight;
2479  }
2480  }
2481  }
2482 
2483  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2484  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2485  RailwayImage->Canvas->FillRect(Rect);
2486 
2487  // write graphics first so text & track overwrite
2488  Track->WriteGraphicsToImage(0, RailwayImage);
2489  // then write text so track overwrites
2490  TextHandler->WriteTextToImage(0, RailwayImage);
2491  Track->WriteTrackToImage(0, RailwayImage);
2492 
2493  RailwayImage->SaveToFile(ImageFileName);
2494  delete RailwayImage;
2495  TrainController->BaseTime = TDateTime::CurrentDateTime();
2497  Screen->Cursor = TCursor(-2); // Arrow
2498  Utilities->CallLogPop(1535);
2499  }
2500  catch(const Exception &e)
2501  {
2502  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2503  {
2504  Screen->Cursor = TCursor(-2); // Arrow;
2505  UnicodeString MessageStr = "Insufficient memory available to store this image";
2506  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2507  }
2508  else
2509  {
2510  ErrorLog(42, e.Message);
2511  }
2512  }
2513 }
2514 
2515 // ---------------------------------------------------------------------------
2516 
2517 void __fastcall TInterface::SaveImageAndGridMenuItemClick(TObject *Sender)
2518 { // need to stop clock in case invoke during operation
2519  try
2520  {
2521  TrainController->LogEvent("SaveImageAndGridMenuItemClick");
2522  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndGridMenuItemClick");
2523  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2524  {
2525  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2526  Utilities->CallLogPop(1696);
2527  return;
2528  }
2529  Screen->Cursor = TCursor(-11); // Hourglass;
2530  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2532  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2533  // format "16/06/2009 20:55:17"
2534  // avoid characters in filename:= / \ : * ? " < > |
2535  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2536  AnsiString ShortName = "";
2537  for(int x = ImageFileName.Length(); x > 0; x--)
2538  {
2539  if(ImageFileName[x] == '\\')
2540  {
2541  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2542  break;
2543  }
2544  }
2545  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2546  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2547  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2548  int HPosMin = Track->GetHLocMin() * 16;
2549  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2550  int VPosMin = Track->GetVLocMin() * 16;
2551  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2552  RailwayImage->Width = HPosMax - HPosMin;
2553  RailwayImage->Height = VPosMax - VPosMin;
2554 
2555  // need to check if there is any text that extends past HPosMax or below VPosMax
2556  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2557  if(!TextHandler->TextVector.empty())
2558  {
2559  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2560  {
2561  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2562  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2563  if(NewWidth > RailwayImage->Width)
2564  {
2565  RailwayImage->Width = NewWidth;
2566  }
2567  if(NewHeight > RailwayImage->Height)
2568  {
2569  RailwayImage->Height = NewHeight;
2570  }
2571  }
2572  }
2573 
2574  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2575  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2576  RailwayImage->Canvas->FillRect(Rect);
2577 
2578  // write the grid first so all else on top
2579  for(int x = 0; x < ((RailwayImage->Width) / 16); x++)
2580  {
2581  for(int y = 0; y < ((RailwayImage->Height) / 16); y++)
2582  {
2583  RailwayImage->Canvas->Draw((x * 16), (y * 16), RailGraphics->bmGrid); // graphic is black on white so no need to change
2584  }
2585  }
2586  // write graphics next so text & track overwrite
2587  Track->WriteGraphicsToImage(1, RailwayImage);
2588  // then write text so track overwrites
2589  TextHandler->WriteTextToImage(1, RailwayImage);
2590  Track->WriteTrackToImage(1, RailwayImage);
2591  RailwayImage->SaveToFile(ImageFileName);
2592  delete RailwayImage;
2593  TrainController->BaseTime = TDateTime::CurrentDateTime();
2595  Screen->Cursor = TCursor(-2); // Arrow
2596  Utilities->CallLogPop(1536);
2597  }
2598  catch(const Exception &e)
2599  {
2600  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2601  {
2602  Screen->Cursor = TCursor(-2); // Arrow;
2603  UnicodeString MessageStr = "Insufficient memory available to store this image";
2604  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2605  }
2606  else
2607  {
2608  ErrorLog(43, e.Message);
2609  }
2610  }
2611 }
2612 // ---------------------------------------------------------------------------
2613 
2614 void __fastcall TInterface::SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
2615 { // need to stop clock in case invoke during operation
2616  try
2617  {
2618  TrainController->LogEvent("SaveImageAndPrefDirsMenuItemClick");
2619  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveImageAndPrefDirsMenuItemClick");
2620  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2621  {
2622  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2623  Utilities->CallLogPop(1697);
2624  return;
2625  }
2626  Screen->Cursor = TCursor(-11); // Hourglass;
2627  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2629  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2630  // format "16/06/2009 20:55:17"
2631  // avoid characters in filename:= / \ : * ? " < > |
2632  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; " + RailwayTitle + ".bmp";
2633  AnsiString ShortName = "";
2634  for(int x = ImageFileName.Length(); x > 0; x--)
2635  {
2636  if(ImageFileName[x] == '\\')
2637  {
2638  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2639  break;
2640  }
2641  }
2642  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2643  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2644  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2645  int HPosMin = Track->GetHLocMin() * 16;
2646  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2647  int VPosMin = Track->GetVLocMin() * 16;
2648  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2649  RailwayImage->Width = HPosMax - HPosMin;
2650  RailwayImage->Height = VPosMax - VPosMin;
2651 
2652  // need to check if there is any text that extends past HPosMax or below VPosMax
2653  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2654  if(!TextHandler->TextVector.empty())
2655  {
2656  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2657  {
2658  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2659  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2660  if(NewWidth > RailwayImage->Width)
2661  {
2662  RailwayImage->Width = NewWidth;
2663  }
2664  if(NewHeight > RailwayImage->Height)
2665  {
2666  RailwayImage->Height = NewHeight;
2667  }
2668  }
2669  }
2670 
2671  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2672  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2673  RailwayImage->Canvas->FillRect(Rect);
2674 
2675  // write graphics first so text & track overwrite
2676  Track->WriteGraphicsToImage(2, RailwayImage);
2677  // then write text so track overwrites
2678  TextHandler->WriteTextToImage(2, RailwayImage);
2679  Track->WriteTrackToImage(2, RailwayImage);
2680  EveryPrefDir->WritePrefDirToImage(0, RailwayImage);
2681  RailwayImage->SaveToFile(ImageFileName);
2682  delete RailwayImage;
2683  TrainController->BaseTime = TDateTime::CurrentDateTime();
2685  Screen->Cursor = TCursor(-2); // Arrow
2686  Utilities->CallLogPop(1566);
2687  }
2688  catch(const Exception &e)
2689  {
2690  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2691  {
2692  Screen->Cursor = TCursor(-2); // Arrow;
2693  UnicodeString MessageStr = "Insufficient memory available to store this image";
2694  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2695  }
2696  else
2697  {
2698  ErrorLog(45, e.Message);
2699  }
2700  }
2701 }
2702 // ---------------------------------------------------------------------------
2703 
2704 void __fastcall TInterface::SaveOperatingImageMenuItemClick(TObject *Sender)
2705 { // need to stop clock
2706  try
2707  {
2708  TrainController->LogEvent("SaveOperatingImageMenuItemClick");
2709  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveOperatingImageMenuItemClick");
2710  if(!DirectoryExists(CurDir + "\\" + IMAGE_DIR_NAME))
2711  {
2712  ShowMessage("Failed to find folder " + IMAGE_DIR_NAME + " in the folder where 'railway.exe' resides. Image can't be saved");
2713  Utilities->CallLogPop(1702);
2714  return;
2715  }
2716  Screen->Cursor = TCursor(-11); // Hourglass;
2717  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
2719 
2720  AnsiString TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
2721  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
2722  AnsiString ImageFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
2723  // format "16/06/2009 20:55:17"
2724  // avoid characters in filename:= / \ : * ? " < > |
2725  ImageFileName = CurDir + "\\" + IMAGE_DIR_NAME + "\\RailwayImage " + ImageFileName + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
2726  "; " + TimetableTitle + ".bmp";
2727  AnsiString ShortName = "";
2728  for(int x = ImageFileName.Length(); x > 0; x--)
2729  {
2730  if(ImageFileName[x] == '\\')
2731  {
2732  ShortName = ImageFileName.SubString(x + 1, ImageFileName.Length() - x - 4);
2733  break;
2734  }
2735  }
2736  ShowMessage("A bitmap file named " + ShortName + " will be created in the Images folder");
2737  Graphics::TBitmap *RailwayImage = new Graphics::TBitmap;
2738  RailwayImage->PixelFormat = pf8bit; // needed to ensure compatibility with track
2739  int HPosMin = Track->GetHLocMin() * 16;
2740  int HPosMax = (Track->GetHLocMax() + 1) * 16;
2741  int VPosMin = Track->GetVLocMin() * 16;
2742  int VPosMax = (Track->GetVLocMax() + 1) * 16;
2743  RailwayImage->Width = HPosMax - HPosMin;
2744  RailwayImage->Height = VPosMax - VPosMin;
2745 
2746  // need to check if there is any text that extends past HPosMax or below VPosMax
2747  // use font height x text length x .7 for new rh calc & font height * 1.5 for new bottom calc
2748  if(!TextHandler->TextVector.empty())
2749  {
2750  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr != TextHandler->TextVector.end(); TextPtr++)
2751  {
2752  int NewWidth = (TextPtr->HPos - HPosMin) + (abs(TextPtr->Font->Height) * TextPtr->TextString.Length() * 0.7);
2753  int NewHeight = (TextPtr->VPos - VPosMin) + (abs(TextPtr->Font->Height) * 1.5);
2754  if(NewWidth > RailwayImage->Width)
2755  {
2756  RailwayImage->Width = NewWidth;
2757  }
2758  if(NewHeight > RailwayImage->Height)
2759  {
2760  RailwayImage->Height = NewHeight;
2761  }
2762  }
2763  }
2764 
2765  RailwayImage->Canvas->Brush->Color = clB5G5R5; // set it all to white initially
2766  TRect Rect(0, 0, RailwayImage->Width, RailwayImage->Height);
2767  RailwayImage->Canvas->FillRect(Rect);
2768 
2769  // write graphics first so text & track overwrite
2770  Track->WriteGraphicsToImage(3, RailwayImage);
2771  // then write text so track overwrites
2772  TextHandler->WriteTextToImage(3, RailwayImage);
2773  Track->WriteOperatingTrackToImage(0, RailwayImage); // need points with single fillets, signals with colours, gaps all connected
2774  AllRoutes->WriteAllRoutesToImage(0, RailwayImage);
2775 // add any locked route markers
2776  if(!AllRoutes->LockedRouteVector.empty())
2777  {
2778  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
2779  {
2780  TOneRoute Route = AllRoutes->GetFixedRouteAt(167, LRVIT->RouteNumber);
2781  int x = Route.PrefDirSize() - 1;
2782  bool BreakFlag = false;
2783  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(188, x);
2784  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
2785  {
2786  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
2787  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
2788  if(!(AllRoutes->TrackIsInARoute(13, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
2789  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
2790  {
2791  BreakFlag = true;
2792  break; // train removed earlier element from route so stop here
2793  }
2794  x--;
2795  PrefDirElement = Route.GetFixedPrefDirElementAt(180, x);
2796  }
2797  if(!BreakFlag)
2798  {
2799  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
2800  {
2801  RailwayImage->Canvas->Draw((PrefDirElement.HLoc - Track->GetHLocMin()) * 16, (PrefDirElement.VLoc - Track->GetVLocMin()) * 16,
2802  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
2803  }
2804  }
2805  }
2806  }
2807  TrainController->WriteTrainsToImage(0, RailwayImage);
2808  RailwayImage->SaveToFile(ImageFileName);
2809  delete RailwayImage;
2810  TrainController->BaseTime = TDateTime::CurrentDateTime();
2812  Screen->Cursor = TCursor(-2); // Arrow
2813  Utilities->CallLogPop(1703);
2814  }
2815  catch(const Exception &e)
2816  {
2817  if(e.Message.Pos("torage") > 0) // 'storage', avoid capitals as may be OS dependent
2818  {
2819  Screen->Cursor = TCursor(-2); // Arrow;
2820  UnicodeString MessageStr = "Insufficient memory available to store this image";
2821  Application->MessageBox(MessageStr.c_str(), L"", MB_OK | MB_ICONWARNING);
2822  }
2823  else
2824  {
2825  ErrorLog(113, e.Message); //NB: DO NOT CHANGE THIS ERROR NUMBER - THE DISPLAYED MESSAGE DEPENDS ON IT
2826  }
2827  }
2828 }
2829 
2830 // ---------------------------------------------------------------------------
2831 
2832 void __fastcall TInterface::SaveHeaderMenu1Click(TObject *Sender)
2833 {
2834 //
2835  try
2836  {
2837  TrainController->LogEvent("SaveHeaderMenu1Click");
2838  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveHeaderMenu1Click");
2839  if(Sender == SaveSessionButton)
2840  {
2841  SaveSessionFlag = true;
2842  }
2843  else if(SavedFileName == "") // use 'Save As' function
2844  {
2845  SaveAsSubroutine(1);
2846  }
2847  else // ordinary save
2848  {
2849  Screen->Cursor = TCursor(-11); // Hourglass;
2850  std::ofstream VecFile(SavedFileName.c_str());
2851  if(!(VecFile.fail()))
2852  {
2856  // save track elements
2857  if(Track->UserGraphicVector.empty())
2858  {
2859  Track->SaveTrack(9, VecFile, false); // false for no graphics (**Active elements** saved as marker)
2860  }
2861  else
2862  {
2863  Track->SaveTrack(10, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
2864  }
2865  // save text elements
2866  TextHandler->SaveText(5, VecFile);
2867  // save PrefDir elements
2868  EveryPrefDir->SavePrefDirVector(8, VecFile);
2869  if(!Track->UserGraphicVector.empty())
2870  {
2871  // save user graphics
2872  Track->SaveUserGraphics(1, VecFile);
2873  }
2874  FileChangedFlag = false;
2875  VecFile.close();
2876  }
2877  else
2878  ShowMessage("Railway failed to save - can't open file");
2879  Screen->Cursor = TCursor(-2); // Arrow
2880  }
2881  Utilities->CallLogPop(1552);
2882  }
2883  catch(const Exception &e)
2884  {
2885  ErrorLog(44, e.Message);
2886  }
2887 }
2888 
2889 // ---------------------------------------------------------------------------
2890 void __fastcall TInterface::LoadSessionMenuItemClick(TObject *Sender)
2891 {
2892  try
2893  {
2894  TrainController->LogEvent("LoadSessionMenuItemClick");
2895  LoadSessionFlag = true; // load session within ClockTimer2
2896  }
2897  catch(const Exception &e)
2898  {
2899  ErrorLog(136, e.Message);
2900  }
2901 }
2902 
2903 // ---------------------------------------------------------------------------
2904 void __fastcall TInterface::ClearAllMenuItemClick(TObject *Sender)
2905 {
2906  try
2907  {
2908  TrainController->LogEvent("ClearAllMenuItemClick");
2909  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClearAllMenuItemClick");
2910  if(ClearEverything(2))
2911  {;
2912  } // no change in action on result
2913  Level1Mode = BaseMode;
2914  SetLevel1Mode(126);
2915  Utilities->CallLogPop(1179);
2916  }
2917  catch(const Exception &e)
2918  {
2919  ErrorLog(137, e.Message);
2920  }
2921 }
2922 
2923 // ---------------------------------------------------------------------------
2924 void __fastcall TInterface::ExportTTMenuItemClick(TObject *Sender)
2925 { // no need to stop clock as can't be called when railway operating
2926  try
2927  {
2928  TrainController->LogEvent("ExportTTMenuItemClick");
2929  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTMenuItemClick");
2930  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
2931  {
2932  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
2933  Utilities->CallLogPop(1699);
2934  return;
2935  }
2936 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
2937 // the message instead, but reset here afterwards
2938  // no need to stop clock as can't select this if operating
2940  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
2941  Utilities->CallLogPop(1573);
2942  }
2943  catch(const Exception &e)
2944  {
2945  ErrorLog(138, e.Message);
2946  }
2947 }
2948 // ---------------------------------------------------------------------------
2949 // Timetable editing functions
2950 
2951 /* Note that during early development the timetable was created outside the program as a .csv file using Excel, it was only later that
2952  the editing functions within the program were developed. Much of the original structure was preserved though to avoid rewriting the
2953  code interpretation functions in TrainUnit.cpp. This is why commas are used as service event separators, and why it is necessary to
2954  convert them to CRLFs for display and back again for internal storage. It is acknowledged that all this makes the editing functions
2955  somewhat cumbersome, and, as ever, if I was starting again I wouldn't do it like that!
2956 
2957  CR & LF review:
2958  These cause problems by the way that different subroutines handle them.
2959 
2960  AnsiStrings can incorporate CRLFs, but the end of an AnsiString is marked by a '\0' character as in 'C' strings.
2961 
2962  In the fstream functions 'getline(char_type* s, streamsize n)' extracts characters from the stream and puts them in buffer 's' until
2963  (a) n-1 characters are stored + '\0' after the n-1 characters;
2964  (b) a '\n' (CRLF) character is found in the stream, in which case a '\0' is added to the buffer after the text that immediately
2965  precedes the CRLF in the stream; and
2966  (c) an eof() is found in the stream, in which case a '\0' is added to the buffer at the end of the text.
2967  Note that if no characters are stored a '\0' is still stored in position [0] of the buffer.
2968 
2969  The << operator in ofstreams, when used with a null terminated string, doesn't store the null. If it is required it has to be
2970  sent explicitly, e.g. file << '\0'. Presumably the same applies for CRLF terminated strings.
2971 
2972 */
2973 // ---------------------------------------------------------------------------
2974 
2975 void __fastcall TInterface::CreateTimetableMenuItemClick(TObject *Sender)
2976 {
2977  try
2978  {
2979  TrainController->LogEvent("CreateTimetableMenuItemClick");
2980  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CreateTimetableMenuItemClick");
2981  CreateEditTTFileName = "";
2982  TimetableEditVector.clear();
2983  TimetableEditPanel->Visible = true;
2984  HighlightPanel->Visible = false;
2985  TimetablePanel->Visible = true;
2986  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
2987  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
2988  OneEntryTimetableMemo->Clear();
2989  AllEntriesTTListBox->Clear();
2990  TTStartTimeBox->Text = "";
2991  AddSubMinsBox->Text = "";
2993  LocationNameComboBox->Clear();
2994  TimetableTitle = ""; // unload any loaded timetable. Added here at v2.1.0
2995  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Added here at v2.1.0
2996  SetCaption(9); // added at v2.1.0 as formerly retained earlier loaded tt name in error
2997  TimetableChangedFlag = false;
2998  TimetableValidFlag = false;
2999  TTEntryChangedFlag = false;
3001  AZOrderButton->Caption = AnsiString("A-Z Order");
3002  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3003  CopiedEntryFlag = false;
3004  NewEntryInPreparationFlag = false;
3005  CopiedEntryStr = "";
3006  TEVPtr = 0;
3008  TTFirstServicePtr = 0;
3009  TTLastServicePtr = 0; // all set to null to begin with
3010 
3011 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3012  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3014  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3015  {
3016  if((Track->TrackVector.at(x).ActiveTrackElementName != "") && (Track->ContinuationNameMap.find(Track->TrackVector.at(x).ActiveTrackElementName))
3017  == Track->ContinuationNameMap.end())
3018  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3019  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
3020  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3021  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3022  }
3023  }
3025  if(!(Track->ActiveTrackElementNameMap.empty()))
3026  {
3027  LocationNameComboBox->Text = "Location names";
3028 // new version at beta v0.2b
3030  ATENIT++)
3031  {
3032  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3033  // continuations as well as other track will be included - earlier version
3034  // would have excluded them
3035  }
3036 
3037 /* old version using LocationNameMultiMap, changed to use ActiveTrackElementNames to avoid including lone concourses and named non-station
3038  locations
3039  TStringList *StringList = new TStringList;
3040  StringList->Clear();//probably already empty but help file doesn't say so
3041  StringList->Sorted = false;//for now
3042  for(TTrack::TLocationNameMultiMapIterator LNMIT = Track->LocationNameMultiMap.begin(); LNMIT != Track->LocationNameMultiMap.end(); LNMIT++)
3043  {
3044  NewKey = LNMIT->first;
3045  if(OldKey != NewKey)//only add new values
3046  {
3047  if(Track->ContinuationNameMap.find(NewKey) == Track->ContinuationNameMap.end())//not a continuation
3048  {
3049  StringList->Add(NewKey);
3050  OldKey = NewKey;
3051  }
3052  }
3053  }
3054  StringList->Sort();
3055  for(int x=0;x<StringList->Count;x++)
3056  {
3057  LocationNameComboBox->Items->Add(StringList->Strings[x]);
3058  }
3059  delete StringList;
3060 */
3061  }
3062  else
3063  {
3064  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3065  }
3067  SetLevel1Mode(82);
3068  Utilities->CallLogPop(1595);
3069  }
3070  catch(const Exception &e)
3071  {
3072  ErrorLog(47, e.Message);
3073  }
3074 }
3075 
3076 // ---------------------------------------------------------------------------
3077 void __fastcall TInterface::EditTimetableMenuItemClick(TObject *Sender)
3078 /* The .ttb file contains a sequence of AnsiStrings separated by null characters. CRLFs may be embedded within the AnsiStrings,
3079  * to cause newlines when displayed. Each AnsiString corresponds to a timetable 'entry'
3080 */
3081 {
3082  try
3083  {
3084  TrainController->LogEvent("EditTimetableMenuItemClick");
3085  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EditTimetableMenuItemClick");
3086  SigImagePanel->Visible = false; //stop panel showing while waiting for name entry
3087  TimetableDialog->Filter = "Timetable file (*.ttb)|*ttb";
3088  CreateEditTTFileName = "";
3089  TimetableEditVector.clear();
3090  TimetableEditPanel->Visible = true;
3091  HighlightPanel->Visible = false;
3092  TimetablePanel->Visible = true;
3093  TimetablePanel->BringToFront(); // in case SaveRailway button visible, want it hidden else obscures the panel text
3094  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3095  OneEntryTimetableMemo->Clear();
3096  AllEntriesTTListBox->Clear();
3097  TTStartTimeBox->Text = "";
3098  AddSubMinsBox->Text = "";
3100  LocationNameComboBox->Clear();
3101  TimetableTitle = ""; // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3102  TrainController->TrainDataVector.clear(); // unload any loaded timetable. Moved here from below at v2.1.0 for consistency with CreateTimetable
3103  SetCaption(8); // added at v2.1.0 as formerly retained earlier loaded tt name in error
3104  TEVPtr = 0;
3106  TTFirstServicePtr = 0;
3107  TTLastServicePtr = 0; // all set to null to begin with
3108  if(TimetableDialog->Execute())
3109  {
3110  CreateEditTTFileName = AnsiString(TimetableDialog->FileName);
3111  TrainController->LogEvent("EditTimetable " + CreateEditTTFileName);
3112  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary); // open in binary to examine each character
3113  if(TTBLFile.is_open())
3114  {
3115  // check doesn't contain any non-ascii characters except CR, LF & '\0', and isn't empty
3116  char c;
3117  while(!TTBLFile.eof())
3118  {
3119  TTBLFile.get(c);
3120  if((c < 32) && (c != 13) && (c != 10) && (c != '\0')) // char is signed by default so values > 127 will be caught as treated as -ve
3121  {
3122  ShowMessage("Timetable file is empty or contains non-ascii characters, codes must be between 20 and 127, or CR or LF");
3123  TTBLFile.close();
3124  Utilities->CallLogPop(1612);
3125  return;
3126  }
3127  }
3128  TTBLFile.close();
3129  }
3130  else
3131  {
3132  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
3133  Utilities->CallLogPop(1597);
3134  return;
3135  }
3136  // reopen again in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
3137  Delay(4, 100); // 100mSec delay between closing & re-opening file
3138  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary);
3139  if(TTBLFile.is_open())
3140  {
3141  TTBLFile.clear(); // to clear eofbit from last read
3142  TTBLFile.seekg(0); // shouldn't be needed but include for safety
3143  TimetableChangedFlag = false;
3144  TimetableValidFlag = false;
3145  TTEntryChangedFlag = false;
3147  AZOrderButton->Caption = AnsiString("A-Z Order");
3148  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
3149  NewEntryInPreparationFlag = false;
3150  CopiedEntryStr = "";
3151  CopiedEntryFlag = false;
3152 // CreateEditTTFileName = TimetableDialog->FileName;
3153  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
3154  {
3155  if(CreateEditTTFileName[x] == '\\')
3156  {
3157  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
3158  break;
3159  }
3160  }
3161  char *TimetableEntryString = new char[10000];
3162  while(true)
3163  {
3164  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
3165  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
3166  { // may still have eof even if read a line, and
3167  // if so need to process it
3168  break;
3169  }
3170  AnsiString OneLine(TimetableEntryString);
3171  TimetableEditVector.push_back(OneLine);
3172  }
3173  TTBLFile.close();
3174  delete TimetableEntryString;
3175  // here with TimetableEditVector compiled
3176  }
3177  else
3178  {
3179  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
3180  Utilities->CallLogPop(1654);
3181  return;
3182  }
3183  }
3184  else // cancelled dialog [section prior to CallLogPop added for v1.3.2 to clear timetable screen if cancel button pressed]
3185  {
3186  CreateEditTTFileName = "";
3187 // set to null to allow a check during error file saving, if not null save the tt being edited to the file (see entry in ExitTTModeButtonClick)
3188  CreateEditTTTitle = ""; // as above
3189  Level1Mode = BaseMode;
3190  SetLevel1Mode(132);
3191  Utilities->CallLogPop(1633);
3192  return;
3193  }
3194 
3196  if(TimetableEditVector.empty())
3197  {
3199  SetLevel1Mode(89);
3200  Utilities->CallLogPop(1614);
3201  return;
3202  }
3203 
3204 // all now set where can be
3206 
3207 // populate LocationNameComboBox if a railway is loaded, but first compile the ActiveTrackElementNameMap
3208  TTrack::TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
3210  for(unsigned int x = 0; x < Track->TrackVector.size(); x++)
3211  {
3212  if((Track->TrackVector.at(x).ActiveTrackElementName != "") && (Track->ContinuationNameMap.find(Track->TrackVector.at(x).ActiveTrackElementName))
3213  == Track->ContinuationNameMap.end())
3214  { // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
3215  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
3216  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
3217  Track->ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
3218  }
3219  }
3221  if(!(Track->ActiveTrackElementNameMap.empty()))
3222  {
3223  LocationNameComboBox->Text = "Location names";
3224 // new version for beta v0.2b
3226  ATENIT++)
3227  {
3228  LocationNameComboBox->Items->Add(ATENIT->first); // continuations excluded during compilation, but a location that includes
3229  // continuations as well as other track will be included - earlier version
3230  // would have excluded them
3231  }
3232  }
3233  else
3234  {
3235  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
3236  }
3238  SetLevel1Mode(83);
3239  Utilities->CallLogPop(1596);
3240  }
3241  catch(const Exception &e)
3242  {
3243  ErrorLog(48, e.Message);
3244  }
3245 }
3246 // ---------------------------------------------------------------------------
3247 
3248 void __fastcall TInterface::ShowHideTTButtonClick(TObject *Sender)
3249 {
3250  try
3251  {
3252  TrainController->LogEvent("ShowHideTTButtonClick");
3253  if(TimetableEditPanel->Visible)
3254  {
3255  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Show");
3256  TimetableEditPanel->Visible = false;
3257  ShowHideTTButton->Hint = "Show the timetable editor Shift S";
3258 // InfoPanel->Visible = false; //changed at v1.3.0 to make it clearer that still in TT mode
3259  InfoPanel->Caption = "Timetable mode: editor hidden"; // as above
3260  }
3261  else
3262  {
3263  ShowHideTTButton->Glyph->LoadFromResourceName(0, "Hide");
3264  TimetableEditPanel->Visible = true;
3265  ShowHideTTButton->Hint = "Hide the timetable editor to see the railway Shift H";
3267  SetLevel1Mode(124);
3268  }
3269  }
3270  catch(const Exception &e)
3271  {
3272  ErrorLog(139, e.Message);
3273  }
3274 }
3275 // ---------------------------------------------------------------------------
3276 
3277 void __fastcall TInterface::NextTTEntryButtonClick(TObject *Sender)
3278 {
3279  try
3280  {
3281  TrainController->LogEvent("NextTTEntryButtonClick");
3282  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NextTTEntryButtonClick");
3283  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3284  {
3285  Utilities->CallLogPop(1683);
3286  return;
3287  }
3288  if(TTCurrentEntryPtr < (TimetableEditVector.end() - 1))
3290  TTEntryChangedFlag = false;
3291  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3292  // position changing in AllEntriesTTListBox
3294  SetLevel1Mode(85);
3295  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3296  {
3298  }
3299  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3300  {
3301  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3302  }
3303  else
3304  {
3305  AllEntriesTTListBox->TopIndex = TopPos;
3306  }
3307  Utilities->CallLogPop(1605);
3308  }
3309  catch(const Exception &e)
3310  {
3311  ErrorLog(50, e.Message);
3312  }
3313 }
3314 
3315 // ---------------------------------------------------------------------------
3316 void __fastcall TInterface::PreviousTTEntryButtonClick(TObject *Sender)
3317 {
3318  try
3319  {
3320  TrainController->LogEvent("PreviousTTEntryButtonClick");
3321  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PreviousTTEntryButtonClick");
3322  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
3323  {
3324  Utilities->CallLogPop(1684);
3325  return;
3326  }
3329  TTEntryChangedFlag = false;
3330  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3331  // position changing in AllEntriesTTListBox
3333  SetLevel1Mode(86);
3334  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3335  {
3337  }
3338  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3339  {
3340  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3341  }
3342  else
3343  {
3344  AllEntriesTTListBox->TopIndex = TopPos;
3345  }
3346  Utilities->CallLogPop(1607);
3347  }
3348  catch(const Exception &e)
3349  {
3350  ErrorLog(51, e.Message);
3351  }
3352 }
3353 
3354 // ---------------------------------------------------------------------------
3355 void __fastcall TInterface::NewTTEntryButtonClick(TObject *Sender)
3356 {
3357  try
3358  {
3359  TrainController->LogEvent("NewTTEntryButtonClick");
3360  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewTTEntryButtonClick");
3361  OneEntryTimetableMemo->Clear();
3362  OneEntryTimetableMemo->SetFocus();
3365  SetLevel1Mode(103);
3366  Utilities->CallLogPop(1615);
3367  }
3368  catch(const Exception &e)
3369  {
3370  ErrorLog(52, e.Message);
3371  }
3372 }
3373 // ---------------------------------------------------------------------------
3374 
3375 void __fastcall TInterface::AddMinsButtonClick(TObject *Sender)
3376 {
3377  try
3378  {
3379  TrainController->LogEvent("AddMinsButtonClick");
3380  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddMinsButtonClick");
3381  bool ValidFlag = true;
3382  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3383  {
3384  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3385  {
3386  ValidFlag = false;
3387  break;
3388  }
3389  }
3390  if(ValidFlag)
3391  {
3392  if(AddSubMinsBox->Text.ToInt() == 0)
3393  ValidFlag = false;
3394  }
3395  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3396  {
3397  Utilities->CallLogPop(1649);
3398  return;
3399  }
3400  TDateTime DummyTime;
3401  int AddMins = AddSubMinsBox->Text.ToInt();
3402  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3403  {
3404  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3405  {
3406  if(TrainController->CheckTimeValidity(25, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3407  {
3408  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3409  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3410  Mins += AddMins;
3411  while(Mins >= 60)
3412  {
3413  Mins -= 60;
3414  Hrs++;
3415  }
3416  if(Hrs > 95)
3417  {
3418  ShowMessage("One or more times excessive, not permitted to exceed 95 hours");
3419  Utilities->CallLogPop(1650);
3420  return;
3421  }
3422  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3423  if(Mins < 10)
3424  MinsStr = "0" + MinsStr;
3425  if(Hrs < 10)
3426  HrsStr = "0" + HrsStr;
3427  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3428  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3429  NewString += HrsStr + ':' + MinsStr;
3430  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3431  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3432  }
3433  }
3434  }
3435 
3436  OneEntryTimetableMemo->HideSelection = true;
3437  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3438  OneEntryTimetableMemo->SelLength = 0;
3439  TimetableValidFlag = false;
3440  TimetableChangedFlag = true;
3441  TTEntryChangedFlag = true;
3443  SetLevel1Mode(91);
3444  Utilities->CallLogPop(1617);
3445  }
3446  catch(const Exception &e)
3447  {
3448  ErrorLog(54, e.Message);
3449  }
3450 }
3451 // ---------------------------------------------------------------------------
3452 
3453 void __fastcall TInterface::SubMinsButtonClick(TObject *Sender)
3454 {
3455  try
3456  {
3457  TrainController->LogEvent("SubMinsButtonClick");
3458  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SubMinsButtonClick");
3459  bool ValidFlag = true;
3460  for(int x = 1; x <= AddSubMinsBox->Text.Length(); x++)
3461  {
3462  if((AddSubMinsBox->Text[x] > '9') || (AddSubMinsBox->Text[x] < '0')) // tested in TTHandler but check here as a safeguard
3463  {
3464  ValidFlag = false;
3465  break;
3466  }
3467  }
3468  if(ValidFlag)
3469  {
3470  if(AddSubMinsBox->Text.ToInt() == 0)
3471  ValidFlag = false;
3472  }
3473  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == "") || (AddSubMinsBox->Text == "") || !ValidFlag)
3474  {
3475  Utilities->CallLogPop(1659);
3476  return;
3477  }
3478  TDateTime DummyTime;
3479  int SubMins = AddSubMinsBox->Text.ToInt();
3480  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3481  {
3482  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
3483  {
3484  if(TrainController->CheckTimeValidity(28, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
3485  {
3486  int Mins = OneEntryTimetableMemo->Lines->Strings[x].SubString(y + 3, 2).ToInt();
3487  int Hrs = OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 2).ToInt();
3488  Mins -= SubMins;
3489  while(Mins < 0)
3490  {
3491  Mins += 60;
3492  Hrs--;
3493  }
3494  if(Hrs < 0)
3495  {
3496  ShowMessage("One or more times are now before 00:00, this is not permitted");
3497  Utilities->CallLogPop(1660);
3498  return;
3499  }
3500  AnsiString MinsStr = AnsiString(Mins), HrsStr = AnsiString(Hrs);
3501  if(Mins < 10)
3502  MinsStr = "0" + MinsStr;
3503  if(Hrs < 10)
3504  HrsStr = "0" + HrsStr;
3505  int StrLength = OneEntryTimetableMemo->Lines->Strings[x].Length();
3506  AnsiString NewString = OneEntryTimetableMemo->Lines->Strings[x].SubString(1, (y - 1)); // up to but not including the time
3507  NewString += HrsStr + ':' + MinsStr;
3508  NewString += OneEntryTimetableMemo->Lines->Strings[x].SubString((y + 5), (StrLength - y - 4));
3509  OneEntryTimetableMemo->Lines->Strings[x] = NewString;
3510  }
3511  }
3512  }
3513  OneEntryTimetableMemo->HideSelection = true;
3514  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
3515  OneEntryTimetableMemo->SelLength = 0;
3516  TimetableValidFlag = false;
3517  TimetableChangedFlag = true;
3518  TTEntryChangedFlag = true;
3520  SetLevel1Mode(92);
3521  Utilities->CallLogPop(1618);
3522  }
3523  catch(const Exception &e)
3524  {
3525  ErrorLog(55, e.Message);
3526  }
3527 }
3528 // ---------------------------------------------------------------------------
3529 
3530 void __fastcall TInterface::CopyTTEntryButtonClick(TObject *Sender)
3531 {
3532  try
3533  {
3534  TrainController->LogEvent("CopyTTEntryButtonClick");
3535  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyTTEntryButtonClick");
3536  if(TTCurrentEntryPtr == 0)
3537  {
3538  Utilities->CallLogPop(1636);
3539  return;
3540  }
3542  CopiedEntryFlag = true;
3543  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3544  // position changing in AllEntriesTTListBox
3546  SetLevel1Mode(93);
3547  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3548  {
3550  }
3551  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3552  {
3553  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3554  }
3555  else
3556  {
3557  AllEntriesTTListBox->TopIndex = TopPos;
3558  }
3559  Utilities->CallLogPop(1619);
3560  }
3561  catch(const Exception &e)
3562  {
3563  ErrorLog(56, e.Message);
3564  }
3565 }
3566 // ---------------------------------------------------------------------------
3567 
3568 void __fastcall TInterface::CutTTEntryButtonClick(TObject *Sender)
3569 {
3570  try
3571  {
3572  TrainController->LogEvent("CutTTEntryButtonClick");
3573  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutTTEntryButtonClick");
3574  if(TTCurrentEntryPtr == 0) // || (*TTCurrentEntryPtr == ""))//safeguard
3575  {
3576  Utilities->CallLogPop(1674);
3577  return;
3578  }
3580  CopiedEntryFlag = true;
3581  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3582  // so use the position in the vector
3584 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3585 // pick up the start time if there is one
3586  TimetableChangedFlag = true;
3587  TimetableValidFlag = false;
3588  TTEntryChangedFlag = false;
3589  TEVPtr = 0;
3591  TTFirstServicePtr = 0;
3592  TTLastServicePtr = 0; // all set to null to begin with
3593  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3594  // position changing in AllEntriesTTListBox
3595  AllEntriesTTListBox->Clear();
3597  if(TimetableEditVector.empty())
3598  {
3600  SetLevel1Mode(109);
3601  Utilities->CallLogPop(1777);
3602  return;
3603  }
3604 
3605 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one //was 'after', changed after v2.4.3
3606 // but vector pointers unreliable after an erase, so use the position in the vector
3607  if(OldVectorPos == 0)
3608  {
3610  }
3611  else
3612  {
3613  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
3614  }
3615  if(TTCurrentEntryPtr == 0)
3616  {
3617  OneEntryTimetableMemo->Clear();
3618  }
3620  SetLevel1Mode(115);
3621  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3622  {
3624  }
3625  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3626  {
3627  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3628  }
3629  else
3630  {
3631  AllEntriesTTListBox->TopIndex = TopPos;
3632  }
3633  Utilities->CallLogPop(1676);
3634  }
3635  catch(const Exception &e)
3636  {
3637  ErrorLog(111, e.Message);
3638  }
3639 }
3640 
3641 // ---------------------------------------------------------------------------
3642 void __fastcall TInterface::PasteTTEntryButtonClick(TObject *Sender)
3643 {
3644  try
3645  {
3646  TrainController->LogEvent("PasteTTEntryButtonClick");
3647  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteTTEntryButtonClick");
3648  if(TTCurrentEntryPtr == 0) // || (CopiedEntryStr == "")) allow blank copies
3649  {
3650  Utilities->CallLogPop(1637);
3651  return;
3652  }
3653  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3654  TimetableEditVector.insert(TTCurrentEntryPtr + 1, CopiedEntryStr); // inserts before the indicated pointer position, i.e. immediately
3655  // after the current Entry - may be at the end
3656  TimetableChangedFlag = true;
3657  TimetableValidFlag = false;
3658  TTEntryChangedFlag = false;
3659  TEVPtr = 0;
3661  TTFirstServicePtr = 0;
3662  TTLastServicePtr = 0; // all set to null to begin with
3663  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3664  // position changing in AllEntriesTTListBox
3665  AllEntriesTTListBox->Clear();
3667  if(TimetableEditVector.empty())
3668  {
3670  SetLevel1Mode(110);
3671  Utilities->CallLogPop(1778);
3672  return;
3673  }
3674 // restore TTCurrentEntryPtr
3675  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3676  TTCurrentEntryPtr++; // advance the pointer to the pasted entry
3677 // CopiedEntryStr = "";//revert to null - no, allow multiple copies
3679  SetLevel1Mode(94);
3680  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3681  {
3683  }
3684  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3685  {
3686  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3687  }
3688  else
3689  {
3690  AllEntriesTTListBox->TopIndex = TopPos;
3691  }
3692  Utilities->CallLogPop(1620);
3693  }
3694  catch(const Exception &e)
3695  {
3696  ErrorLog(57, e.Message);
3697  }
3698 }
3699 // ---------------------------------------------------------------------------
3700 
3701 void __fastcall TInterface::DeleteTTEntryButtonClick(TObject *Sender)
3702 {
3703  try
3704  {
3705  TrainController->LogEvent("DeleteTTEntryButtonClick");
3706  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteTTEntryButtonClick");
3707  if(TTCurrentEntryPtr == 0)
3708  {
3709  Utilities->CallLogPop(1645);
3710  return;
3711  }
3712  UnicodeString MessageStr = "Are you sure this entry should be deleted?";
3713  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
3714  if(button == IDNO)
3715  {
3716  Utilities->CallLogPop(1663);
3717  return;
3718  }
3719  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an erase,
3720  // so use the position in the vector
3722 
3723 // now need to rebuild all the pointers & the AllEntriesTTListBox so repeat the process from EditTimetableMenuItemClick
3724 // pick up the start time if there is one
3725  TimetableChangedFlag = true;
3726  TimetableValidFlag = false;
3727  TTEntryChangedFlag = false;
3728  TEVPtr = 0;
3730  TTFirstServicePtr = 0;
3731  TTLastServicePtr = 0; // all set to null to begin with
3732  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3733  // position changing in AllEntriesTTListBox
3734  AllEntriesTTListBox->Clear();
3736  if(TimetableEditVector.empty())
3737  {
3739  SetLevel1Mode(111);
3740  Utilities->CallLogPop(1779);
3741  return;
3742  }
3743 // reset the TTCurrentEntryPtr to the Entry before the erased one if there is one
3744 // but vector pointers unreliable after an erase, so use the position in the vector
3745  if(OldVectorPos == 0)
3746  {
3748  }
3749  else
3750  {
3751  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos - 1;
3752  }
3753  if(TTCurrentEntryPtr == 0)
3754  {
3755  OneEntryTimetableMemo->Clear();
3756  }
3758  SetLevel1Mode(95);
3759  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3760  {
3762  }
3763  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3764  {
3765  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3766  }
3767  else
3768  {
3769  AllEntriesTTListBox->TopIndex = TopPos;
3770  }
3771  Utilities->CallLogPop(1621);
3772  }
3773  catch(const Exception &e)
3774  {
3775  ErrorLog(58, e.Message);
3776  }
3777 }
3778 // ---------------------------------------------------------------------------
3779 
3780 void __fastcall TInterface::SaveTTEntryButtonClick(TObject *Sender)
3781 {
3782  try
3783  {
3784  TrainController->LogEvent("SaveTTEntryButtonClick");
3785  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTEntryButtonClick");
3786 /* allow blank lines to be saved
3787  AnsiString ContentStr = OneEntryTimetableMemo->Text;
3788  if((ContentStr == "\r\n") || (ContentStr == "\n") || (ContentStr == ""))
3789  {
3790  Utilities->CallLogPop(1679);
3791  return;
3792  }
3793 */
3794  AnsiString TempStr = "";
3795  bool ActiveLine = false;
3796  if(TTCurrentEntryPtr > 0)
3797  {
3798  if(*TTCurrentEntryPtr != "")
3799  {
3801  {
3802  ActiveLine = true;
3803  // need to add commas after each line in OneEntryTimetableMemo exept the last, where have '\0'
3804  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
3805  {
3806  for(int y = 1; y <= OneEntryTimetableMemo->Lines->Strings[x].Length(); y++)
3807  {
3808  TempStr += OneEntryTimetableMemo->Lines->Strings[x][y];
3809  }
3810  if(x < (OneEntryTimetableMemo->Lines->Count - 1))
3811  {
3812  TempStr += ',';
3813  }
3814  // No need to add a '\n' as a '\0' is added automatically as a string delimiter. If add '\n' then it is treated as a blank line and
3815  // ends the timetable
3816  }
3817  // strip any excess commas from the end
3818  if(TempStr != "")
3819  {
3820  while(TempStr[TempStr.Length()] == ',')
3821  {
3822  TempStr = TempStr.SubString(1, TempStr.Length() - 1);
3823  if(TempStr == "")
3824  break;
3825  }
3826  }
3827  }
3828  }
3829  }
3830  if(!ActiveLine)
3831  {
3832  TempStr = OneEntryTimetableMemo->Text; // Note that if the entry was intended as a service but goes in as plain text because
3833  // the service & entry pointers aren't yet set, then CRLFs will be converted to commas in
3834  // CompileAllEntriesMemoAndSetPointers if it appears after the start time
3835  // and before a blank line or end of file, so the syntax check will work OK
3836  }
3837  if(AZOrderButton->Caption == AnsiString("Original Order"))
3838  {
3840  }
3841  TimetableValidFlag = false;
3842  TimetableChangedFlag = true;
3843  TTEntryChangedFlag = false;
3844  int TopPos;
3845  if(TTCurrentEntryPtr == 0)
3846  {
3848  }
3850  {
3851  (*TTCurrentEntryPtr) = TempStr;
3852  // need to reset the AllEntriesTTListBox in case the headcode has changed
3853  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3854  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3855  // position changing in AllEntriesTTListBox
3856  AllEntriesTTListBox->Clear();
3858  if(TimetableEditVector.empty())
3859  {
3861  SetLevel1Mode(112);
3862  Utilities->CallLogPop(1780);
3863  return;
3864  }
3865  // restore TTCurrentEntryPtr
3866  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3867  }
3868  else
3869  {
3870  NewEntryInPreparationFlag = false;
3871  if(TTCurrentEntryPtr != 0)
3872  {
3873  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // vector pointers unreliable after an insert
3874  TimetableEditVector.insert(TTCurrentEntryPtr + 1, TempStr); // inserts before the indicated pointer position, which may be at the end
3875  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3877  }
3878  else
3879  {
3880  TimetableEditVector.insert(TimetableEditVector.end(), TempStr); // inserts before the indicated pointer position
3882  }
3883  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the current position
3884  TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
3885  // position changing in AllEntriesTTListBox
3886  AllEntriesTTListBox->Clear();
3888  if(TimetableEditVector.empty())
3889  {
3891  SetLevel1Mode(113);
3892  Utilities->CallLogPop(1781);
3893  return;
3894  }
3895 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
3896  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
3897  {
3899  }
3900  else
3901  {
3902  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
3903  }
3904  }
3906  SetLevel1Mode(96);
3907  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
3908  {
3910  }
3911  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
3912  {
3913  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
3914  }
3915  else
3916  {
3917  AllEntriesTTListBox->TopIndex = TopPos;
3918  }
3919  Utilities->CallLogPop(1622);
3920  }
3921  catch(const Exception &e)
3922  {
3923  ErrorLog(59, e.Message);
3924  }
3925 }
3926 // ---------------------------------------------------------------------------
3927 
3928 void __fastcall TInterface::SaveTTButtonClick(TObject *Sender)
3929 {
3930  try
3931  {
3932  TrainController->LogEvent("SaveTTButtonClick");
3933  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTButtonClick");
3934  if(TimetableEditVector.empty())
3935  {
3936  ShowMessage("Timetable is empty, can't save an empty timetable");
3937  Utilities->CallLogPop(1685);
3938  return;
3939  }
3940  std::ofstream TTBLFile;
3941  if(CreateEditTTFileName != "")
3942  {
3943  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
3944  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
3945  }
3946  else
3947  {
3948  if(SaveTTDialog->Execute())
3949  {
3950  CreateEditTTFileName = AnsiString(SaveTTDialog->FileName);
3951  for(int x = CreateEditTTFileName.Length(); x > 0; x--)
3952  {
3953  if(CreateEditTTFileName[x] == '\\')
3954  {
3955  CreateEditTTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
3956  break;
3957  }
3958  }
3959  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
3960  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
3961  }
3962  else //cancelled dialog
3963  {
3965  SetLevel1Mode(137);
3966  Utilities->CallLogPop(2205);
3967  return;
3968  }
3969  }
3970  if(TTBLFile.is_open())
3971  {
3972  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
3973  {
3974  TTBLFile << (*TEVPtr).c_str() << '\0';
3975  }
3976  TimetableChangedFlag = false;
3977  TTBLFile.close();
3978  }
3979  else
3980  {
3981  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
3982  }
3984  SetLevel1Mode(97);
3985  Utilities->CallLogPop(1623);
3986  }
3987  catch(const Exception &e)
3988  {
3989  ErrorLog(60, e.Message);
3990  }
3991 }
3992 // ---------------------------------------------------------------------------
3993 
3994 void __fastcall TInterface::SaveTTAsButtonClick(TObject *Sender)
3995 {
3996  try
3997  {
3998  TrainController->LogEvent("SaveTTAsButtonClick");
3999  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SaveTTAsButtonClick");
4000  if(TimetableEditVector.empty())
4001  {
4002  ShowMessage("Timetable is empty, can't save an empty timetable");
4003  Utilities->CallLogPop(1686);
4004  return;
4005  }
4006  std::ofstream TTBLFile;
4007  if(SaveTTDialog->Execute())
4008  {
4009  CreateEditTTFileName = SaveTTDialog->FileName;
4010  for(int x = SaveTTDialog->FileName.Length(); x > 0; x--)
4011  {
4012  if(SaveTTDialog->FileName[x] == '\\')
4013  {
4014  CreateEditTTTitle = SaveTTDialog->FileName.SubString(x + 1, SaveTTDialog->FileName.Length() - x - 4);
4015  break;
4016  }
4017  }
4018  TTBLFile.open(CreateEditTTFileName.c_str(), std::ios_base::binary); // if text then each time sees a "\r\n" pair enters "\r\n\n" because '\n'
4019  // on its own causes "\r\n' to ne inserted, binary just enters characters as they are
4020  }
4021  else //cancelled dialog
4022  {
4024  SetLevel1Mode(138);
4025  Utilities->CallLogPop(2206);
4026  return;
4027  }
4028  if(TTBLFile.is_open())
4029  {
4030  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4031  {
4032  TTBLFile << (*TEVPtr).c_str() << '\0';
4033  }
4034  TimetableChangedFlag = false;
4035  TTBLFile.close();
4036  }
4037  else
4038  {
4039  ShowMessage(CreateEditTTFileName + " failed to open, ensure not already open in another application");
4040  }
4042  SetLevel1Mode(117);
4043  Utilities->CallLogPop(1667);
4044  }
4045  catch(const Exception &e)
4046  {
4047  ErrorLog(108, e.Message);
4048  }
4049 }
4050 // ---------------------------------------------------------------------------
4051 
4052 void __fastcall TInterface::TTServiceSyntaxCheckButtonClick(TObject *Sender)
4053 {
4054  try
4055  {
4056  TrainController->LogEvent("TTServiceSyntaxCheckButtonClick");
4057  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTServiceSyntaxCheckButtonClick");
4058  int Count = 1; // anything > 0 OK as if 0 still seeking a start time
4059  bool EndOfFile = false;
4060  bool FinalCallFalse = false;
4061  bool GiveMessagesTrue = true;
4062  bool CheckLocationsExistInRailway = false;
4063  if(RlyFile)
4064  CheckLocationsExistInRailway = true;
4065 // TrainController->AnyHeadCodeValid = true; //don't fail here because of an unrestricted headcode, if no good will find when validate (dropped at v0.6b)
4066  if(TrainController->ProcessOneTimetableLine(2, Count, *TTCurrentEntryPtr, EndOfFile, FinalCallFalse, GiveMessagesTrue, CheckLocationsExistInRailway))
4067  // return true for success
4068  {
4069  ShowMessage(
4070  "The basic syntax seems OK but this check is very limited. Other aspects can only be checked by validating the whole timetable with the appropriate railway (.rly) loaded");
4071  }
4073  SetLevel1Mode(98);
4074  Utilities->CallLogPop(1624);
4075  }
4076  catch(const Exception &e)
4077  {
4078  ErrorLog(61, e.Message);
4079  }
4080 }
4081 // ---------------------------------------------------------------------------
4082 
4083 void __fastcall TInterface::ValidateTimetableButtonClick(TObject *Sender)
4084 {
4085  try
4086  {
4087  TrainController->LogEvent("ValidateTimetableButtonClick");
4088  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ValidateTimetableButtonClick");
4089  // reset all message flags, stops them being given twice new at v2.4.0
4090  TrainController->SSHigh = false;
4091  TrainController->MRSHigh = false;
4092  TrainController->MRSLow = false;
4093  TrainController->MassHigh = false;
4094  TrainController->BFHigh = false;
4095  TrainController->BFLow = false;
4096  TrainController->PwrHigh = false;
4097  TrainController->SigSHigh = false;
4098  TrainController->SigSLow = false;
4099  if(CreateEditTTFileName == "")
4100  {
4101  Utilities->CallLogPop(1664);
4102  return;
4103  }
4104  bool CheckLocationsExistInRailwayTrue = true;
4105  if(TrainController->TimetableIntegrityCheck(2, CreateEditTTFileName.c_str(), true, CheckLocationsExistInRailwayTrue)) // messages = true
4106  {
4107  Screen->Cursor = TCursor(-11); // Hourglass;
4108  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4109  if(TTBLFile.is_open())
4110  {
4111  if(BuildTrainDataVectorForValidateFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue)) // messages = true
4112  {
4113  ShowMessage("Timetable integrity OK");
4114  TimetableValidFlag = true;
4115 // TrainController->TrainDataVector.clear(); keep this so can export a formatted tt
4116  };
4117  }
4118  else
4119  {
4120  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
4121  }
4122  Screen->Cursor = TCursor(-2); // Arrow
4123  } // if(TimetableIntegrityCheck
4124  else
4125  {
4126 // ShowMessage("Timetable preliminary integrity check failed"); dropped in v2.4.0 as messages given in all called functions
4127  }
4129  SetLevel1Mode(99);
4130  Utilities->CallLogPop(1625);
4131  }
4132  catch(const Exception &e)
4133  {
4134  ErrorLog(62, e.Message);
4135  }
4136 }
4137 
4138 // ---------------------------------------------------------------------------
4139 void __fastcall TInterface::MoveTTEntryUpButtonClick(TObject *Sender)
4140 {
4141  try
4142  {
4143  TrainController->LogEvent("MoveTTEntryUpButtonClick");
4144  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryUpButtonClick");
4145  if(TTCurrentEntryPtr == 0)
4146  {
4147  Utilities->CallLogPop(1634);
4148  return;
4149  }
4150  if(TTCurrentEntryPtr < (TimetableEditVector.begin() + 1)) // shouldn't reach here but return if do
4151  {
4152  Utilities->CallLogPop(1632);
4153  return;
4154  }
4155  TEVPtr = TTCurrentEntryPtr - 1; // find earlier Entry
4156  AnsiString TempStr = *TEVPtr;
4158  *TTCurrentEntryPtr = TempStr;
4160  TimetableChangedFlag = true;
4161  TimetableValidFlag = false;
4162 
4163 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4164  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4165  // position changing in AllEntriesTTListBox
4166  AllEntriesTTListBox->Clear();
4167  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4169 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4170  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4171  {
4173  }
4174  else
4175  {
4176  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4177  }
4179  SetLevel1Mode(100);
4180  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4181  {
4183  }
4184  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4185  {
4186  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4187  }
4188  else
4189  {
4190  AllEntriesTTListBox->TopIndex = TopPos;
4191  }
4192  Utilities->CallLogPop(1626);
4193  }
4194  catch(const Exception &e)
4195  {
4196  ErrorLog(63, e.Message);
4197  }
4198 }
4199 // ---------------------------------------------------------------------------
4200 
4201 void __fastcall TInterface::MoveTTEntryDownButtonClick(TObject *Sender)
4202 {
4203  try
4204  {
4205  TrainController->LogEvent("MoveTTEntryDownButtonClick");
4206  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveTTEntryDownButtonClick");
4207  if(TTCurrentEntryPtr == 0)
4208  {
4209  Utilities->CallLogPop(1635);
4210  return;
4211  }
4212  if(TTCurrentEntryPtr >= (TimetableEditVector.end() - 1)) // shouldn't reach here but return if do
4213  {
4214  Utilities->CallLogPop(1678);
4215  return;
4216  }
4217  TEVPtr = TTCurrentEntryPtr + 1; // find later Entry
4218  AnsiString TempStr = *TEVPtr;
4220  *TTCurrentEntryPtr = TempStr;
4222  TimetableChangedFlag = true;
4223  TimetableValidFlag = false;
4224 
4225 // now rebuild AllEntriesTTListBox, DisplayOneTTLineInPanel will highlight it
4226  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4227  // position changing in AllEntriesTTListBox
4228  AllEntriesTTListBox->Clear();
4229  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4231 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4232  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4233  {
4235  }
4236  else
4237  {
4238  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4239  }
4241  SetLevel1Mode(101);
4242  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4243  {
4245  }
4246  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4247  {
4248  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4249  }
4250  else
4251  {
4252  AllEntriesTTListBox->TopIndex = TopPos;
4253  }
4254  Utilities->CallLogPop(1627);
4255  }
4256  catch(const Exception &e)
4257  {
4258  ErrorLog(64, e.Message);
4259  }
4260 }
4261 
4262 // ---------------------------------------------------------------------------
4263 void __fastcall TInterface::CancelTTEntryButtonClick(TObject *Sender)
4264 {
4265  try
4266  {
4267  TrainController->LogEvent("CancelTTActionButtonClick");
4268  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelTTActionButtonClick");
4269  TTEntryChangedFlag = false;
4271  {
4272  NewEntryInPreparationFlag = false;
4273  OneEntryTimetableMemo->Clear();
4274  }
4275  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4276  // position changing in AllEntriesTTListBox
4278  SetLevel1Mode(102);
4279  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < TopPos)
4280  {
4282  }
4283  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (TopPos + 45))
4284  {
4285  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
4286  }
4287  else
4288  {
4289  AllEntriesTTListBox->TopIndex = TopPos;
4290  }
4291  Utilities->CallLogPop(1630);
4292  }
4293  catch(const Exception &e)
4294  {
4295  ErrorLog(102, e.Message);
4296  }
4297 }
4298 
4299 // ---------------------------------------------------------------------------
4300 void __fastcall TInterface::RestoreTTButtonClick(TObject *Sender)
4301 {
4302  try
4303  {
4304  TrainController->LogEvent("RestoreTTButtonClick");
4305  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RestoreTTButtonClick");
4307  {
4308  UnicodeString MessageStr = "All changes to the timetable will be lost - proceed?";
4309  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4310  if(button == IDNO)
4311  {
4312  Utilities->CallLogPop(1651);
4313  return;
4314  }
4315  }
4316 
4317  // repeat from EditTimetableMenuItemClick, but no need to check for non-ascii characters
4318  // open in binary mode so the "\r\n" pairs stay as they are rather than being entered as '\n'
4319  std::ifstream TTBLFile(CreateEditTTFileName.c_str(), std::ios_base::binary);
4320  if(TTBLFile.is_open())
4321  {
4322  TimetableChangedFlag = false;
4323  TimetableValidFlag = false;
4324  TTEntryChangedFlag = false;
4325  NewEntryInPreparationFlag = false;
4326  CopiedEntryFlag = false;
4327  CopiedEntryStr = "";
4328  TimetableEditVector.clear();
4329  OneEntryTimetableMemo->Clear();
4330  AllEntriesTTListBox->Clear();
4331  TTStartTimeBox->Text = "";
4332  AddSubMinsBox->Text = "";
4333  TEVPtr = 0;
4335  TTFirstServicePtr = 0;
4336  TTLastServicePtr = 0; // all set to null to begin with
4337  char *TimetableEntryString = new char[10000];
4338  while(true)
4339  {
4340  TTBLFile.getline(TimetableEntryString, 10000, '\0'); // pick up the entire AnsiString, including any embedded newlines
4341  if(TTBLFile.eof() && (TimetableEntryString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
4342  { // may still have eof even if read a line, and
4343  // if so need to process it
4344  break;
4345  }
4346  AnsiString OneLine(TimetableEntryString);
4347  TimetableEditVector.push_back(OneLine);
4348  }
4349  TTBLFile.close();
4350  delete TimetableEntryString;
4351  // here with TimetableEditVector compiled
4352  }
4353  else
4354  {
4355  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
4356  Utilities->CallLogPop(1655);
4357  return;
4358  }
4359 
4361  if(TimetableEditVector.empty())
4362  {
4364  SetLevel1Mode(114);
4365  Utilities->CallLogPop(1782);
4366  return;
4367  }
4368 // all now set where can be
4370 // end of repeat from EditTimetableMenuItemClick
4371 
4373  SetLevel1Mode(104);
4374  Utilities->CallLogPop(1652);
4375  }
4376  catch(const Exception &e)
4377  {
4378  ErrorLog(104, e.Message);
4379  }
4380 }
4381 
4382 // ---------------------------------------------------------------------------
4383 void __fastcall TInterface::ExportTTButtonClick(TObject *Sender)
4384 {
4385  try
4386  {
4387  TrainController->LogEvent("ExportTTButtonClick");
4388  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExportTTButtonClick");
4389  if(!DirectoryExists(CurDir + "\\" + FORMATTEDTT_DIR_NAME))
4390  {
4391  ShowMessage("Failed to find folder " + FORMATTEDTT_DIR_NAME + " in the folder where 'railway.exe' resides. Timetable can't be exported");
4392  Utilities->CallLogPop(1698);
4393  return;
4394  }
4395 // Screen->Cursor = TCursor(-11); // Hourglass; - no good setting here as it's reset by ShowMessage in CreateFormattedTimetable. It's set there after
4396 // the message instead, but reset here afterwards
4397  AnsiString TTTitle;
4399  {
4400  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
4401  {
4402  if(CreateEditTTFileName[x] == '\\')
4403  {
4404  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
4405  break;
4406  }
4407  }
4409  }
4410  Screen->Cursor = TCursor(-2); // Arrow - reset after above function returns
4412  SetLevel1Mode(116);
4413  Utilities->CallLogPop(1662);
4414  }
4415  catch(const Exception &e)
4416  {
4417  ErrorLog(107, e.Message);
4418  }
4419 }
4420 
4421 // ---------------------------------------------------------------------------
4422 void __fastcall TInterface::TTTextButtonClick(TObject *Sender)
4423 {
4424  try
4425  {
4426  TrainController->LogEvent("TTTextButtonClick");
4427  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTTextButtonClick");
4428 /*
4429  if(TTStartTimePtr == 0)
4430  {
4431  OneEntryTimetableMemo->Clear();
4432  TTStartTimeBox->SetFocus();
4433  Utilities->CallLogPop(1673);
4434  return;
4435  }
4436 */
4437  int SelPos = OneEntryTimetableMemo->SelStart;
4438  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4439  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4440  OneEntryTimetableMemo->Text = FirstPart + ((TButton*)Sender)->Caption + LastPart;
4441  OneEntryTimetableMemo->SelStart = SelPos + ((TButton*)Sender)->Caption.Length();
4442  TTEntryChangedFlag = true;
4443  OneEntryTimetableMemo->SetFocus();
4445  SetLevel1Mode(119);
4446  Utilities->CallLogPop(1672);
4447  }
4448  catch(const Exception &e)
4449  {
4450  ErrorLog(110, e.Message);
4451  }
4452 }
4453 
4454 // ---------------------------------------------------------------------------
4455 void __fastcall TInterface::ExitTTModeButtonClick(TObject *Sender)
4456 {
4457  try
4458  {
4459  TrainController->LogEvent("ExitTTCreateEditButtonClick");
4460  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitTTCreateEditButtonClick");
4462  {
4463  UnicodeString MessageStr = "The timetable has changed.\n\nAre you sure you want to exit without saving it?";
4464  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
4465  if(button == IDNO)
4466  {
4467  Utilities->CallLogPop(1603);
4468  return;
4469  }
4470  }
4471  TimetableChangedFlag = false;
4472  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
4473  // added for Beta v0.2b
4474  CreateEditTTTitle = ""; // as above
4475  ConflictPanel->Visible = false;
4476  Level1Mode = BaseMode;
4477  SetLevel1Mode(84);
4478  Utilities->CallLogPop(1606);
4479  }
4480  catch(const Exception &e)
4481  {
4482  ErrorLog(49, e.Message);
4483  }
4484 }
4485 
4486 // ---------------------------------------------------------------------------
4487 void __fastcall TInterface::LocationNameComboBoxClick(TObject *Sender)
4488 {
4489  try
4490  {
4491  TrainController->LogEvent("LocationNameComboBoxClick");
4492  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxClick");
4493  if(TTStartTimePtr != 0)
4494  {
4495  LocationNameComboBox->SelectAll();
4496  int SelPos = OneEntryTimetableMemo->SelStart;
4497  AnsiString FirstPart = OneEntryTimetableMemo->Text.SubString(1, SelPos);
4498  AnsiString LastPart = OneEntryTimetableMemo->Text.SubString(SelPos + 1, OneEntryTimetableMemo->Text.Length() - SelPos);
4499  OneEntryTimetableMemo->Text = FirstPart + LocationNameComboBox->SelText + LastPart;
4500  OneEntryTimetableMemo->SelStart = SelPos + LocationNameComboBox->SelText.Length();
4501  TTEntryChangedFlag = true;
4502  OneEntryTimetableMemo->SetFocus();
4504  SetLevel1Mode(118);
4505  }
4506  Utilities->CallLogPop(1669);
4507  }
4508  catch(const Exception &e)
4509  {
4510  ErrorLog(109, e.Message);
4511  }
4512 }
4513 
4514 // ---------------------------------------------------------------------------
4515 void __fastcall TInterface::OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4516 {
4517  try
4518  {
4519 // TrainController->LogEvent("OneEntryTimetableMemoKeyUp"); drop this - too many entries
4520  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OneEntryTimetableMemoKeyUp");
4522  {
4523  Utilities->CallLogPop(1716);
4524  return;
4525  }
4526  TimetableChangedFlag = true;
4527  TTEntryChangedFlag = true;
4528  TimetableValidFlag = false;
4530  SetLevel1Mode(127);
4531  Utilities->CallLogPop(1629);
4532  }
4533  catch(const Exception &e)
4534  {
4535  ErrorLog(66, e.Message);
4536  }
4537 }
4538 
4539 // ---------------------------------------------------------------------------
4540 void __fastcall TInterface::AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4541 {
4542 // forces a recheck for whether addmins/submins buttons should be enabled
4543  try
4544  {
4545  TrainController->LogEvent("AddSubMinsBoxKeyUp");
4546  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AddSubMinsBoxKeyUp");
4548  SetLevel1Mode(108);
4549  Utilities->CallLogPop(1658);
4550  }
4551  catch(const Exception &e)
4552  {
4553  ErrorLog(106, e.Message);
4554  }
4555 }
4556 
4557 // ---------------------------------------------------------------------------
4558 void __fastcall TInterface::LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
4559 {
4560  try
4561  {
4562  TrainController->LogEvent("LocationNameComboBoxKeyUp");
4563  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LocationNameComboBoxKeyUp");
4564  if(!Track->LocationNameMultiMap.empty())
4565  {
4566  LocationNameComboBox->Text = "Location names";
4567  }
4568  else
4569  {
4570  LocationNameComboBox->Text = "No locations (listed when a railway with names is loaded)";
4571  }
4572  Utilities->CallLogPop(1677);
4573  }
4574  catch(const Exception &e)
4575  {
4576  ErrorLog(112, e.Message);
4577  }
4578 }
4579 
4580 // ---------------------------------------------------------------------------
4581 
4582 void __fastcall TInterface::AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button,
4583  TShiftState Shift, int X, int Y)
4584 {
4585 // Select the item pointed to unless a 'save entry' is pending in which case ignore
4586  try
4587  {
4588  TrainController->LogEvent("AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4589  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AllEntriesTTListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4590  if((TTCurrentEntryPtr == 0) || TimetableEditVector.empty())
4591  {
4592  Utilities->CallLogPop(1687);
4593  return;
4594  }
4595  if(TTEntryChangedFlag || NewEntryInPreparationFlag) // if a save/cancel pending don't permit anything else
4596  {
4597  Utilities->CallLogPop(1688);
4598  return;
4599  }
4600  // find item required - 13 pixels per line of text
4601  int TopPos = AllEntriesTTListBox->TopIndex; // need to store this & reset it after SetLevel1Mode to prevent the scroll
4602  // position changing in AllEntriesTTListBox
4603  if((TopPos + (Y / 13)) >= AllEntriesTTListBox->Items->Count)
4604  {
4606  }
4607  else
4608  {
4609  TTCurrentEntryPtr = TimetableEditVector.begin() + (Y / 13) + TopPos;
4610  }
4611  int OldVectorPos = TTCurrentEntryPtr - TimetableEditVector.begin(); // save the old position
4613 // reset the TTCurrentEntryPtr after CompileAllEntriesMemoAndSetPointers
4614  if(OldVectorPos >= TimetableEditVector.end() - TimetableEditVector.begin() - 1)
4615  {
4617  }
4618  else
4619  {
4620  TTCurrentEntryPtr = TimetableEditVector.begin() + OldVectorPos;
4621  }
4623  SetLevel1Mode(120);
4624  AllEntriesTTListBox->TopIndex = TopPos; // reset it after SetLevel1Mode to prevent the scroll position changing
4625  Utilities->CallLogPop(1648);
4626  }
4627  catch(const Exception &e)
4628  {
4629  ErrorLog(103, e.Message);
4630  }
4631 }
4632 
4633 // ---------------------------------------------------------------------------
4634 
4635 void __fastcall TInterface::OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
4636 {
4637 // Mouseup rather than Mousedown so shows floating label when over train
4638  try
4639  {
4640  TrainController->LogEvent("OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4641  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OAListBoxMouseUp," + AnsiString(X) + "," + AnsiString(Y));
4642  if(Track->RouteFlashFlag || Track->PointFlashFlag) // no action
4643  {
4644  Utilities->CallLogPop(2087);
4645  return;
4646  }
4648  {
4649  Utilities->CallLogPop(2088);
4650  return;
4651  }
4653  // find item required - 13 pixels per line of text
4654  int TopPos = OAListBox->TopIndex;
4655  int OAIndex;
4656  if((TopPos + (Y / 13)) >= OAListBox->Items->Count) // if click beyond end of list ignore
4657  {
4658  Utilities->CallLogPop(2089);
4659  return;
4660  }
4661  else
4662  {
4663  OACurrentEntryPtr = TrainController->OpTimeToActMultiMap.begin();
4664  std::advance(OACurrentEntryPtr, ((Y / 13) + TopPos));
4665  }
4666  int HPos;
4667  int VPos;
4668  int TrackVectorPosition;
4669  int TrainIDorTVPos = OACurrentEntryPtr->second.second;
4670  if(TrainIDorTVPos >= 0) // running train, so value is the TrainID
4671  {
4672  if(TrainController->TrainExistsAtIdent(0, TrainIDorTVPos)) // added at v2.4.0 in case train removed but still in OA list as not updated yet
4673  // see LiWinDom error report on Discord 23/04/20. Also needed for click OAListBox before any trains show,
4674  // as notified by Rokas Serys by email on 16/05/20
4675  {
4676  TrackVectorPosition = TrainController->TrainVectorAtIdent(43, TrainIDorTVPos).LeadElement;
4677  }
4678  else
4679  {
4680  Utilities->CallLogPop(2155); // if not there then ignore
4681  return;
4682  }
4683  }
4684  else // train to enter at a continuation, so value is -TVPos of continuation - 1
4685  {
4686  TrackVectorPosition = -(TrainIDorTVPos + 1);
4687  }
4688  HPos = (Track->TrackElementAt(926, TrackVectorPosition).HLoc * 16);
4689  VPos = (Track->TrackElementAt(927, TrackVectorPosition).VLoc * 16);
4690  // now want to set the offsets to display HPos & VPos in the centre of the screen
4691  Display->DisplayOffsetH = (HPos - MainScreen->Width / 2) / 16; // ScreenPosH = HPos - (DisplayOffsetH * 16)
4692  Display->DisplayOffsetV = (VPos - MainScreen->Height / 2) / 16;
4693  int ScreenPosH = HPos - (Display->DisplayOffsetH * 16);
4694  int ScreenPosV = VPos - (Display->DisplayOffsetV * 16);
4695  if(Display->ZoomOutFlag) // panel displays in either zoom mode
4696  {
4697  Display->ZoomOutFlag = false;
4699  }
4700  ClearandRebuildRailway(72); // if was zoomed out this displays the track because until ZoomOutFlag reset PlotOutput plots nothing
4701  TPoint MainScreenPoint(ScreenPosH + 8, ScreenPosV + 8); // new v2.2.0 add 8 to centre pointer in element
4702  TPoint CursPos = MainScreen->ClientToScreen(MainScreenPoint); // accurate funtion to convert from local to global co-ordinates
4703  Mouse->CursorPos = CursPos;
4704  Utilities->CallLogPop(2090);
4705  }
4706  catch(const Exception &e)
4707  {
4708  ErrorLog(200, e.Message);
4709  }
4710 }
4711 
4712 // ---------------------------------------------------------------------------
4713 
4715 {
4716  enum
4717  {
4718  PreStartTime, ActiveSegment, PostEnd} Segment;
4719  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CompileAllEntriesMemoAndSetPointers");
4720  AllEntriesTTListBox->Clear();
4721  TEVPtr = 0;
4722  TTStartTimePtr = 0;
4723  TTFirstServicePtr = 0;
4724  TTLastServicePtr = 0; // all set to null to begin with
4725  if(TimetableEditVector.empty())
4726  {
4727  TTCurrentEntryPtr = 0;
4728  Utilities->CallLogPop(1681);
4729  return;
4730  }
4731  Segment = PreStartTime;
4732  for(TEVPtr = TimetableEditVector.begin(); TEVPtr != TimetableEditVector.end(); TEVPtr++)
4733  {
4734  if(Segment == PreStartTime) // looking for the start time
4735  {
4736  TDateTime TempTime; // dummy
4737  if(TrainController->CheckTimeValidity(33, *TEVPtr, TempTime))
4738  {
4739  TTStartTimePtr = TEVPtr; // TTStartTimeBox text set in TTHandler
4740  AllEntriesTTListBox->Items->Add("START " + (*TEVPtr).SubString(1, 5));
4741  Segment = ActiveSegment;
4742  continue;
4743  }
4744  else
4745  {
4746  if(*TEVPtr == "")
4747  {
4748  AllEntriesTTListBox->Items->Add("- Blank");
4749  }
4750  else
4751  {
4752  AnsiString CurrentStr = *TEVPtr;
4753  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
4754  {
4755  CurrentStr = CurrentStr.SubString(1, 10); // limit length for LH window
4756  for(int x = 1; x < CurrentStr.Length(); x++)
4757  {
4758  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
4759  {
4760  CurrentStr = CurrentStr.SubString(1, (x - 1));
4761  }
4762  }
4763  }
4764  AllEntriesTTListBox->Items->Add("- " + CurrentStr);
4765  }
4766  continue;
4767  }
4768  }
4769  if(Segment == ActiveSegment)
4770  {
4771  if(*TEVPtr != "")
4772  {
4773  if((*TEVPtr)[1] != '*')
4774  {
4776  ConvertCRLFsToCommas(0, *TEVPtr); // This needed because an entry intended as a service might have skipped the conversion in
4777  // SaveTTEntryButtonClick - see comment in that function
4778  if(TTFirstServicePtr == 0)
4779  {
4781  }
4783  }
4784  AnsiString Entry = *TEVPtr;
4785  if(Entry[1] == '*')
4786  Entry = "Comment";
4787  else
4788  {
4789  int SCPos = Entry.Pos(';'); // semicolon
4790  int CPos = Entry.Pos(','); // comma
4791  // 5 possibilities: no comma & no semicolon - just text - enter 1st 12 characters
4792  // both, comma before semicolon, i.e text on its own line, semicolon on next line - e.g. service headcode but no
4793  // description - enter the text up to the comma
4794  // both, semicolon before comma, normal - enter text up to the semicolon
4795  // comma & no semicolon, one or more lines of text without any semicolons - enter the text up to the comma
4796  // semicolon & no comma - enter text up to the semicolon
4797  if((CPos == 0) && (SCPos == 0))
4798  {
4799  Entry = Entry.SubString(1, 12);
4800  }
4801  else if((CPos > 0) && (SCPos > 0) && (CPos < SCPos))
4802  {
4803  Entry = Entry.SubString(1, CPos - 1);
4804  }
4805  else if((CPos > 0) && (SCPos > 0) && (CPos > SCPos))
4806  {
4807  Entry = Entry.SubString(1, SCPos - 1);
4808  }
4809  else if((CPos > 0) && (SCPos == 0))
4810  {
4811  Entry = Entry.SubString(1, CPos - 1);
4812  }
4813  else
4814  {
4815  Entry = Entry.SubString(1, SCPos - 1);
4816  }
4817  }
4818  AllEntriesTTListBox->Items->Add(Entry);
4819  continue;
4820  }
4821  else
4822  {
4823  Segment = PostEnd;
4824  AllEntriesTTListBox->Items->Add("END (Blank)");
4825  continue;
4826  }
4827  }
4828  if(Segment == PostEnd)
4829  {
4830  if(*TEVPtr == "")
4831  {
4832  AllEntriesTTListBox->Items->Add("+ Blank");
4833  }
4834  else
4835  {
4836  AnsiString CurrentStr = *TEVPtr;
4837  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
4838  {
4839  CurrentStr = CurrentStr.SubString(1, 10);
4840  for(int x = 1; x < CurrentStr.Length(); x++)
4841  {
4842  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
4843  {
4844  CurrentStr = CurrentStr.SubString(1, (x - 1));
4845  }
4846  }
4847  }
4848  AllEntriesTTListBox->Items->Add("+ " + CurrentStr);
4849  }
4850  continue;
4851  }
4852  }
4853  if(TTStartTimePtr == 0)
4854  {
4855  TTStartTimeBox->Text = "";
4856  }
4857  TTCurrentEntryPtr = TTLastServicePtr; // may well be reset outside this function but need to ensure that it has a valid value on exit, even if it's null
4858  Utilities->CallLogPop(1680);
4859 }
4860 // ---------------------------------------------------------------------------
4861 
4862 void __fastcall TInterface::AZOrderButtonClick(TObject *Sender)
4863 {
4864  try
4865  {
4866  if(TimetableEditVector.empty())
4867  {
4868  return; // should be able to access this if it is but keep in for safety
4869  }
4870  TrainController->LogEvent("AZOrderClick");
4871  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AZOrderClick");
4872  if(AZOrderButton->Caption == AnsiString("A-Z Order"))
4873  {
4874  TTEVPtr SortStart, SortEnd;
4875  UnicodeString MessageStr =
4876  "If you wish to preserve the original order don't make any changes whilst in alphabetical order.\n\nIn that case use alphabetical order to find the service required, click it to display it, then revert to the original order where the same service will be displayed and can be changed.";
4877  Application->MessageBox(MessageStr.c_str(), L"Please Note:", MB_OK | MB_ICONWARNING);
4880  SortStart = TimetableEditVector.begin(); // if no start time set sort from beginning
4881  if(TTFirstServicePtr != NULL)
4882  {
4883  SortStart = TTFirstServicePtr;
4884  }
4885  SortEnd = TimetableEditVector.end(); // if no last service set sort to end
4886  if(TTLastServicePtr != NULL)
4887  {
4888  SortEnd = TTLastServicePtr + 1;
4889  }
4890  std::sort(SortStart, SortEnd);
4892  bool CurrentEntryChanged = false;
4893  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
4894  {
4895  if(TTSelectedEntry == *x)
4896  {
4897  TTCurrentEntryPtr = x;
4898  CurrentEntryChanged = true;
4899  }
4900  }
4901  if(!CurrentEntryChanged)
4902  {
4904  }
4905  AZOrderButton->Caption = AnsiString("Original Order");
4906  AZOrderButton->Hint = AnsiString("Arrange services in original order Toggle with Shift+ Z");
4907  }
4908  else
4909  {
4911  {
4912  UnicodeString MessageStr =
4913  "Reverting to the original order will discard any changes made whilst in alphabetical order.\n\nTo preserve the changes click 'No', then save the timetable or use 'save as' if you wish to keep the original timetable.\n\nDo you wish to proceed?";
4914  int button = Application->MessageBox(MessageStr.c_str(), L"Warning!", MB_YESNO | MB_ICONWARNING);
4915  if(button == IDNO)
4916  {
4917  TimetableChangedFlag = true;
4918  TimetableValidFlag = false;
4920  SetLevel1Mode(135);
4921  Utilities->CallLogPop(2166);
4922  return;
4923  }
4924  }
4928  bool CurrentEntryChanged = false;
4929  for(TTimetableEditVector::iterator x = TimetableEditVector.begin(); x < TimetableEditVector.end(); x++)
4930  {
4931  if(TTSelectedEntry == *x)
4932  {
4933  TTCurrentEntryPtr = x;
4934  CurrentEntryChanged = true;
4935  }
4936  }
4937  if(!CurrentEntryChanged)
4938  {
4940  }
4941  AZOrderButton->Caption = AnsiString("A-Z Order");
4942  AZOrderButton->Hint = AnsiString("Arrange services in alphabetical order Toggle with Shift+ Z");
4943  }
4944  TimetableChangedFlag = true;
4945  TimetableValidFlag = false;
4948  SetLevel1Mode(136);
4949  Utilities->CallLogPop(2165);
4950  }
4951  catch(const Exception &e)
4952  {
4953  ErrorLog(211, e.Message);
4954  }
4955 }
4956 
4957 // ---------------------------------------------------------------------------
4958 
4959 void TInterface::ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
4960 {
4961  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertCRLFsToCommas," + ConvStr);
4962  AnsiString OutStr = "";
4963  int x = 1; // AnsiString arrays start at 1
4964 
4965  while(x < ConvStr.Length()) // skip the last character as looking for CRLF pairs, i.e. '\r' followed by '\n'
4966  {
4967  if((ConvStr[x] == '\r') && (ConvStr[x + 1] == '\n'))
4968  {
4969  OutStr += ',';
4970  x++;
4971  x++;
4972  }
4973  else
4974  {
4975  OutStr += ConvStr[x];
4976  x++;
4977  }
4978  }
4979  if(x == ConvStr.Length())
4980  OutStr += ConvStr[x]; // add the last character
4981 
4982 // strip any excess commas from the end
4983  if(OutStr != "")
4984  {
4985  while(OutStr[OutStr.Length()] == ',')
4986  {
4987  OutStr = OutStr.SubString(1, OutStr.Length() - 1);
4988  if(OutStr == "")
4989  break; // if consisted of just commas then without this would fail on range error when becomes a null string
4990  }
4991  }
4992  ConvStr = OutStr;
4993  if(ConvStr == "")
4994  ConvStr = ','; // don't return a null or will fail, OK to return a comma on its own as will be ignored during ProcessOneTimetableLine
4995  // when AllCommas will be true
4996  Utilities->CallLogPop(1846);
4997 }
4998 
4999 // ---------------------------------------------------------------------------
5000 
5002 {
5003 /* CreateEditTTFileName set if a TT file loaded (even if empty), the pointers TTStartTimePtr, TTFirstServicePtr, TTLastServicePtr provide
5004  relevant information - if null then not set. TTCurrentEntryPtr is set to the Entry to be displayed or null if there's no start time or no
5005  entries
5006 */
5007  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableHandler");
5008  PreviousTTEntryButton->Enabled = false;
5009  NextTTEntryButton->Enabled = false;
5010  AddMinsButton->Enabled = false;
5011  SubMinsButton->Enabled = false;
5012  CopyTTEntryButton->Enabled = false;
5013  CutTTEntryButton->Enabled = false;
5014  PasteTTEntryButton->Enabled = false;
5015  DeleteTTEntryButton->Enabled = false;
5016  SaveTTEntryButton->Enabled = false;
5017  SaveTTButton->Enabled = false;
5018  SaveTTAsButton->Enabled = false;
5019  ValidateTimetableButton->Enabled = false;
5020  AZOrderButton->Enabled = false;
5021  TTServiceSyntaxCheckButton->Enabled = false;
5022  NewTTEntryButton->Enabled = false;
5023  MoveTTEntryUpButton->Enabled = false;
5024  MoveTTEntryDownButton->Enabled = false;
5025  CancelTTEntryButton->Enabled = false;
5026  RestoreTTButton->Enabled = false;
5027  ExportTTButton->Enabled = false;
5028  ConflictAnalysisButton->Enabled = false;
5029  ExitTTModeButton->Enabled = true;
5030 
5032  {
5033  AZOrderButton->Enabled = true;
5034  }
5035 
5037  TimetableValidFlag = false; // should always be the case anyway but include here to be sure
5038 
5039  if(CreateEditTTFileName == "")
5040  {
5041  TimetableNameLabel->Caption = "Creating new timetable: not yet saved";
5042  }
5043  else
5044  {
5045  TimetableNameLabel->Caption = "Editing timetable: " + CreateEditTTTitle;
5046  }
5047 
5048  if(TTStartTimePtr != 0) // Null means start time not yet set
5049  {
5050  TTStartTimeBox->Text = (*TTStartTimePtr).SubString(1, 5); // 1st 5 chars = time if validity check OK
5051  }
5052 // start time now set & displayed
5053 
5055  {
5056  InfoPanel->Visible = true;
5057  InfoPanel->Caption = "Select option or change entry";
5058  if(RailwayTitle != "")
5059  {
5060  ShowHideTTButton->Enabled = true;
5061  }
5062  else
5063  {
5064  ShowHideTTButton->Enabled = false;
5065  }
5066  ExitTTModeButton->Enabled = true;
5067  AllEntriesTTListBox->Enabled = true;
5068  AnsiString AnsiAddSubText(AddSubMinsBox->Text);
5069  if((AnsiAddSubText != "") && AreAnyTimesInCurrentEntry())
5070  {
5071  bool ValidFlag = true;
5072  for(int x = 1; x <= AnsiAddSubText.Length(); x++)
5073  {
5074  if((AnsiAddSubText[x] > '9') || (AnsiAddSubText[x] < '0'))
5075  {
5076  ValidFlag = false;
5077  break;
5078  }
5079  }
5080  if(ValidFlag)
5081  {
5082  if(AnsiAddSubText.ToInt() != 0)
5083  {
5084  AddMinsButton->Enabled = true;
5085  SubMinsButton->Enabled = true;
5086  }
5087  }
5088  }
5090  {
5091  RestoreTTButton->Enabled = true;
5092  }
5094  { // Need !TimetableChangedFlag because the changed TT must be saved before validation - it's the TT file that is checked
5095  // so if it is changed but not saved, the 'correct' file will check OK but the changed TT may well not be valid
5096  ValidateTimetableButton->Enabled = true;
5097  }
5099  {
5100  ExportTTButton->Enabled = true;
5101  ConflictAnalysisButton->Enabled = true;
5102  }
5103  if(TTCurrentEntryPtr != 0)
5104  {
5105  CopyTTEntryButton->Enabled = true;
5106  CutTTEntryButton->Enabled = true;
5107  DeleteTTEntryButton->Enabled = true;
5108  }
5109  if((TimetableChangedFlag) && !TimetableEditVector.empty())
5110  {
5111  SaveTTButton->Enabled = true;
5112  }
5113  if(!TimetableEditVector.empty())
5114  {
5115  SaveTTAsButton->Enabled = true;
5116  }
5118  {
5119  NewTTEntryButton->Enabled = true;
5120  }
5121  if((TTCurrentEntryPtr > 0) && !TimetableEditVector.empty())
5122  {
5123  if((TimetableEditVector.end() - 1) > TTCurrentEntryPtr)
5124  {
5125  NextTTEntryButton->Enabled = true;
5126  MoveTTEntryDownButton->Enabled = true;
5127  }
5129  {
5130  PreviousTTEntryButton->Enabled = true;
5131  MoveTTEntryUpButton->Enabled = true;
5132  }
5133  }
5134  if(TTCurrentEntryPtr > 0)
5135  {
5136  if(*TTCurrentEntryPtr != "")
5137  {
5139  {
5140  TTServiceSyntaxCheckButton->Enabled = true;
5141  }
5142  }
5143  }
5144  if(CopiedEntryFlag)
5145  {
5146  PasteTTEntryButton->Enabled = true;
5147  }
5148  OneEntryTimetableMemo->Clear(); // don't clear if Entry changed
5149  if(TTCurrentEntryPtr > 0)
5150  {
5151 // if(*TTCurrentEntryPtr != "") leave this out or fails to highlight blank line entries
5153  {
5154  bool ServiceEntry = true;
5155  DisplayOneTTLineInPanel(0, *TTCurrentEntryPtr, ServiceEntry);
5156  }
5157  else
5158  {
5159  bool ServiceEntry = false;
5160  DisplayOneTTLineInPanel(1, *TTCurrentEntryPtr, ServiceEntry);
5161  }
5162  }
5163  }
5164  else
5165  {
5166  CancelTTEntryButton->Enabled = true;
5167  SaveTTEntryButton->Enabled = true;
5168  ShowHideTTButton->Enabled = false;
5169  ExitTTModeButton->Enabled = false;
5170  AllEntriesTTListBox->Enabled = false; // to stop entries being selected
5171  InfoPanel->Caption = "Add or change entry then save it, or cancel";
5172  InfoPanel->Visible = true;
5173  }
5174  Utilities->CallLogPop(1600);
5175 }
5176 
5177 // ---------------------------------------------------------------------------
5178 void TInterface::DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
5179 {
5180  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisplayOneTTLineInPanel," + Data + ", " +
5181  AnsiString((short)ServiceEntry));
5182  OneEntryTimetableMemo->Clear();
5183  if(ServiceEntry)
5184  {
5185  TrainController->StripSpaces(1, Data);
5186  while(true)
5187  {
5188  int CommaPos = Data.Pos(',');
5189  if((CommaPos == 0) && (Data != ""))
5190  {
5191  CommaPos = Data.Length() + 1;
5192  }
5193  OneEntryTimetableMemo->Lines->Add(Data.SubString(1, CommaPos - 1));
5194  if(Data.Length() <= CommaPos)
5195  break;
5196  Data = Data.SubString(CommaPos + 1, Data.Length() - CommaPos);
5197  }
5198  }
5199  else
5200  {
5201  OneEntryTimetableMemo->Text = Data;
5202  }
5203  int TotalLines = OneEntryTimetableMemo->Lines->Count; // remove excess lines at bottom
5204 
5205  while((OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "") || (OneEntryTimetableMemo->Lines->Strings[TotalLines - 1] == "\r\n"))
5206  {
5207  OneEntryTimetableMemo->Lines->Delete(TotalLines - 1);
5208  TotalLines--;
5209  if(TotalLines < 1)
5210  break;
5211  }
5212  OneEntryTimetableMemo->HideSelection = true;
5213  OneEntryTimetableMemo->SelStart = 0; // need this & next command to set cursor to the top
5214  OneEntryTimetableMemo->SelLength = 0;
5216  Utilities->CallLogPop(1602);
5217 }
5218 // ---------------------------------------------------------------------------
5219 
5221 {
5222  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighlightOneEntryInAllEntriesTTListBox," + AnsiString(Position));
5223  if(TimetableEditVector.empty() || (AllEntriesTTListBox->Items->Count == 0))
5224  {
5225  HighlightPanel->Top = 32;
5226  HighlightPanel->Caption = "";
5227  HighlightPanel->Width = 100;
5228  HighlightPanel->Visible = false;
5229  }
5230  else
5231  {
5232  AnsiString CurrentStr = AllEntriesTTListBox->Items->Strings[Position];
5233  if(CurrentStr != "") // strip any non alphanumeric characters (specifically \r or \n)
5234  {
5235  for(int x = 1; x < CurrentStr.Length(); x++)
5236  {
5237  if((CurrentStr[x] < 32) || (CurrentStr[1] > 126))
5238  {
5239  CurrentStr = CurrentStr.SubString(1, (x - 1));
5240  }
5241  }
5242  }
5243  HighlightPanel->Top = 32 + (Position * 13) - (AllEntriesTTListBox->TopIndex * 13);
5244  if(HighlightPanel->Top < 32)
5245  HighlightPanel->Visible = false;
5246  else
5247  HighlightPanel->Visible = true; // doesn't matter if goes off the bottom as it becomes invisible as then it's off its parent panel
5248  HighlightPanel->Caption = CurrentStr;
5249  if(AllEntriesTTListBox->Items->Count > 46) //because the scrollbar will be present
5250  HighlightPanel->Width = 82;
5251  else
5252  HighlightPanel->Width = 100;
5253  }
5254  Utilities->CallLogPop(1709);
5255 }
5256 
5257 // ---------------------------------------------------------------------------
5259 {
5260  if((TTCurrentEntryPtr == 0) || (*TTCurrentEntryPtr == ""))
5261  {
5262  return false;
5263  }
5264  TDateTime DummyTime;
5265  bool TimesPresent = false;
5266 
5267  for(int x = 0; x < OneEntryTimetableMemo->Lines->Count; x++)
5268  {
5269  for(int y = 1; y < (OneEntryTimetableMemo->Lines->Strings[x].Length() - 3); y++)
5270  {
5271  if(TrainController->CheckTimeValidity(20, OneEntryTimetableMemo->Lines->Strings[x].SubString(y, 5), DummyTime))
5272  {
5273  TimesPresent = true;
5274  break;
5275  }
5276  }
5277  if(TimesPresent)
5278  break;
5279  }
5280  return TimesPresent;
5281 }
5282 
5283 // ---------------------------------------------------------------------------
5284 // end of Timetable editing functions
5285 // ---------------------------------------------------------------------------
5286 void __fastcall TInterface::ExitMenuItemClick(TObject *Sender)
5287 {
5288  try
5289  {
5290  TrainController->LogEvent("ExitMenuItemClick");
5291  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ExitMenuItemClick");
5293  {
5294  UnicodeString MessageStr =
5295  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
5296  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5297  if(button == IDNO)
5298  {
5299  Utilities->CallLogPop(1711);
5300  return;
5301  }
5302  }
5303  if(FileChangedFlag)
5304  {
5305  UnicodeString MessageStr = "The railway has changed, exit without saving?";
5306  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
5307  if(button == IDNO)
5308  {
5309  Utilities->CallLogPop(1180);
5310  return;
5311  }
5312  }
5313  if((TempTTFileName != "") && FileExists(TempTTFileName))
5314  {
5315  DeleteFile(TempTTFileName);
5316  }
5317  Utilities->CallLogPop(1181);
5318  Application->Terminate();
5319  }
5320  catch(const Exception &e)
5321  {
5322  ErrorLog(140, e.Message);
5323  }
5324 }
5325 // ---------------------------------------------------------------------------
5326 
5327 void __fastcall TInterface::TrackInfoOnOffMenuItemClick(TObject *Sender)
5328 {
5329  try
5330  {
5331  TrainController->LogEvent("TrackInfoOnOffMenuItemClick");
5332  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrackInfoOnOffMenuItemClick");
5333  if(TrackInfoOnOffMenuItem->Caption == "Show")
5334  {
5335  TrackInfoOnOffMenuItem->Caption = "Hide";
5336  }
5337  else
5338  {
5339  TrackInfoOnOffMenuItem->Caption = "Show";
5340  }
5341  Utilities->CallLogPop(1183);
5342  }
5343  catch(const Exception &e)
5344  {
5345  ErrorLog(173, e.Message);
5346  }
5347 }
5348 // ---------------------------------------------------------------------------
5349 
5350 void __fastcall TInterface::TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
5351 {
5352  try
5353  {
5354  TrainController->LogEvent("TrainStatusInfoOnOffMenuItemClick");
5355  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainStatusInfoOnOffMenuItemClick");
5356  if(TrainStatusInfoOnOffMenuItem->Caption == "Show Status")
5357  {
5358  TrainStatusInfoOnOffMenuItem->Caption = "Hide Status";
5359  }
5360  else
5361  {
5362  TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
5363  }
5364  Utilities->CallLogPop(1184);
5365  }
5366  catch(const Exception &e)
5367  {
5368  ErrorLog(141, e.Message);
5369  }
5370 }
5371 
5372 // ---------------------------------------------------------------------------
5373 void __fastcall TInterface::TrainTTInfoOnOffMenuItemClick(TObject *Sender)
5374 {
5375  try
5376  {
5377  TrainController->LogEvent("TrainTTInfoOnOffMenuItemClick");
5378  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TrainTTInfoOnOffMenuItemClick");
5379  if(TrainTTInfoOnOffMenuItem->Caption == "Show Timetable")
5380  {
5381  TrainTTInfoOnOffMenuItem->Caption = "Hide Timetable";
5382  }
5383  else
5384  {
5385  TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
5386  }
5387  Utilities->CallLogPop(1185);
5388  }
5389  catch(const Exception &e)
5390  {
5391  ErrorLog(142, e.Message);
5392  }
5393 }
5394 
5395 // ---------------------------------------------------------------------------
5396 // Dragging Functions
5397 // ---------------------------------------------------------------------------
5398 void __fastcall TInterface::AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
5399 {
5400 // allow in zoom out mode
5401  try
5402  {
5403 // TrainController->LogEvent("AcceptDragging"); drop this, have too many
5404  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",AcceptDragging");
5405  if((Source == PerformancePanel) || (Source == PerformancePanelLabel) || (Source == PerformanceLogBox))
5406  {
5407  Accept = true;
5408  int PPLeft = PerformancePanel->Left;
5409  int PPTop = PerformancePanel->Left;
5410 
5411  PPLeft = Mouse->CursorPos.x - PerformancePanelDragStartX;
5412  PPTop = Mouse->CursorPos.y - PerformancePanelDragStartY;
5413  if((PPLeft + PerformancePanel->Width) < 32)
5414  PPLeft = 32 - PerformancePanel->Width;
5415  if(PPLeft > (MainScreen->Left + MainScreen->Width))
5416  PPLeft = MainScreen->Left + MainScreen->Width;
5417  if((PPTop + PerformancePanel->Height) < MainScreen->Top)
5418  PPTop = MainScreen->Top - PerformancePanel->Height;
5419  if(PPTop > (MainScreen->Top + MainScreen->Height - 20))
5420  PPTop = MainScreen->Top + MainScreen->Height - 20;
5421  PerformancePanel->Left = PPLeft;
5422  PerformancePanel->Top = PPTop;
5423  }
5424  else if((Source == OperatorActionPanel) || (Source == OAPanelLabel))
5425  // not the listbox because that used for selecting trains
5426  {
5427  Accept = true;
5428  int OALeft = OperatorActionPanel->Left;
5429  int OATop = OperatorActionPanel->Left;
5430 
5431  OALeft = Mouse->CursorPos.x - OperatorActionPanelDragStartX;
5432  OATop = Mouse->CursorPos.y - OperatorActionPanelDragStartY;
5433  if((OALeft + OperatorActionPanel->Width) < 32)
5434  OALeft = 32 - OperatorActionPanel->Width;
5435  if(OALeft > (MainScreen->Left + MainScreen->Width))
5436  OALeft = MainScreen->Left + MainScreen->Width;
5437  if((OATop + OperatorActionPanel->Height) < MainScreen->Top)
5438  OATop = MainScreen->Top - OperatorActionPanel->Height;
5439  if(OATop > (MainScreen->Top + MainScreen->Height - 20))
5440  OATop = MainScreen->Top + MainScreen->Height - 20;
5441  OperatorActionPanel->Left = OALeft;
5442  OperatorActionPanel->Top = OATop;
5443  }
5444  else
5445  Accept = false;
5446  Utilities->CallLogPop(1186);
5447  }
5448  catch(const Exception &e)
5449  {
5450  ErrorLog(143, e.Message);
5451  }
5452 }
5453 
5454 // ---------------------------------------------------------------------------
5455 void __fastcall TInterface::PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
5456 {
5457 // allow in zoom out mode
5458  try
5459  {
5460  TrainController->LogEvent("PerformancePanelStartDrag");
5461  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelStartDrag");
5462  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
5463  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
5464  Utilities->CallLogPop(1187);
5465  }
5466  catch(const Exception &e)
5467  {
5468  ErrorLog(144, e.Message);
5469  }
5470 }
5471 // ---------------------------------------------------------------------------
5472 
5473 void __fastcall TInterface::OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject) // new v2.2.0
5474 
5475 {
5476 // allow in zoom out mode
5477  try
5478  {
5479  TrainController->LogEvent("OperatorActionPanelStartDrag");
5480  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionPanelStartDrag");
5481  OperatorActionPanelDragStartX = Mouse->CursorPos.x - OperatorActionPanel->Left;
5482  OperatorActionPanelDragStartY = Mouse->CursorPos.y - OperatorActionPanel->Top;
5483  Utilities->CallLogPop(2091);
5484  }
5485  catch(const Exception &e)
5486  {
5487  ErrorLog(201, e.Message);
5488  }
5489 }
5490 
5491 // ---------------------------------------------------------------------------
5492 // Mouse Functions
5493 // ---------------------------------------------------------------------------
5494 void __fastcall TInterface::MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
5495  // caller function - stops master clock
5496 {
5497 // have to allow in zoom out mode
5498  try
5499  {
5500  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseDown," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5501  bool ClockState = Utilities->Clock2Stopped;
5502  Utilities->Clock2Stopped = true;
5503 
5504  RestoreFocusPanel->Enabled = true; // these added at v2.0.0 to restore navigation keys to move screen when a panel had focus
5505  RestoreFocusPanel->Visible = true; // because then these buttons just cycled through the panel buttons. Added in place of the
5506  RestoreFocusPanel->SetFocus(); // section in ClockTimer2 where focus restored every clock cycle, because then the help screen
5507  RestoreFocusPanel->Visible = false; // was hidden. At least now help is only hidden when the screen clicked, which is normal
5508  RestoreFocusPanel->Enabled = false; // behaviour, and can tell user that can restore navigation keys just by clicking the screen
5509 
5511  {
5512  if(!Display->ZoomOutFlag)
5513  MainScreenMouseDown2(0, Button, Shift, X, Y);
5514  else
5515  MainScreenMouseDown3(0, Button, Shift, X, Y);
5516  }
5517  Utilities->Clock2Stopped = ClockState;
5518  Utilities->CallLogPop(33);
5519  }
5520  catch(const Exception &e)
5521  {
5522  ErrorLog(19, e.Message);
5523  }
5524 }
5525 
5526 // ---------------------------------------------------------------------------
5527 void TInterface::MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
5528 {
5529  try
5530  {
5531  TrainController->LogEvent("MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
5532  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown2," + AnsiString(Button) + "," + AnsiString(X) +
5533  "," + AnsiString(Y));
5534  // unplot GapFlash graphics if plotted & cancel gap flashing (either key down)
5535  // but not in ZoomOut mode - so can switch between modes & keep gaps flashing
5537  {
5540  Track->GapFlashFlag = false;
5541  }
5542  int HLoc, VLoc;
5543  Track->GetTrackLocsFromScreenPos(1, HLoc, VLoc, X, Y);
5544  int NoOffsetX, NoOffsetY;
5545  Track->GetTruePositionsFromScreenPos(0, NoOffsetX, NoOffsetY, X, Y);
5546  if(Button == mbRight) // track, PrefDir or text erase, PrefDir/route truncate, or take signaller control of train
5547  {
5548  // this routine new at v2.1.0. Allows railway moving for zoom-in mode when no element at HLoc & VLoc
5549  int Dummy; // unused in next function
5550  AnsiString Text = ""; //needed for TextFound but not used
5551  if(!Track->TrackElementPresentAtHV(0, HLoc, VLoc) && !Track->InactiveTrackElementPresentAtHV(0, HLoc, VLoc) && !Track->UserGraphicPresentAtHV(0, X, Y, Dummy) &&
5552  !TextHandler->TextFound(0, X + (Display->DisplayOffsetH * 16), Y + (Display->DisplayOffsetV * 16), Text))
5553  {
5556  WholeRailwayMoving = true;
5557  Screen->Cursor = TCursor(-22); // Four arrows;
5558  }
5559 
5560  else if(Level2TrackMode == AddText)
5561  {
5562  TrainController->LogEvent("mbRight + AddText");
5564  if(TextHandler->TextFound(1, NoOffsetX, NoOffsetY, Text))
5565  {
5566  if(TextHandler->TextErase(0, NoOffsetX, NoOffsetY, Text)) // erase text in vector
5567  {
5569  if(NoRailway())
5570  {
5571  EditMenu->Enabled = false;
5572  }
5573  else
5574  EditMenu->Enabled = true;
5575  }
5576  }
5577  SetLevel2TrackMode(57); // to remove 'move text' if last text item removed
5578  Utilities->CallLogPop(34);
5579  return;
5580  }
5581  else if(Level2TrackMode == AddGraphic)
5582  {
5583  TrainController->LogEvent("mbRight + AddGraphic");
5584  if(Track->UserGraphicVector.empty()) // no user graphics
5585  {
5586  Utilities->CallLogPop(2180);
5587  return;
5588  }
5589  int UGIVecPos;
5590  if(Track->UserGraphicPresentAtHV(1, X, Y, UGIVecPos))
5591  {
5592  Track->UserGraphicVector.erase(Track->UserGraphicVector.begin() + UGIVecPos);
5594  if(NoRailway())
5595  {
5596  EditMenu->Enabled = false;
5597  }
5598  else
5599  EditMenu->Enabled = true;
5600  }
5601  Utilities->CallLogPop(2181);
5602  return;
5603  }
5604 
5605  else if(Level2TrackMode == AddTrack)
5606  {
5607  TrainController->LogEvent("mbRight + AddTrack");
5608  bool TrackEraseSuccessfulFlag;
5609  int ErasedTrackVectorPosition;
5610  Screen->Cursor = TCursor(-11); // Hourglass;
5611  Track->EraseTrackElement(1, HLoc, VLoc, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, true);
5612  if(TrackEraseSuccessfulFlag)
5613  {
5614  if(ErasedTrackVectorPosition > -1)
5615  EveryPrefDir->RealignAfterTrackErase(0, ErasedTrackVectorPosition);
5618  ClearandRebuildRailway(5); // to ensure location named elements plotted correctly & replot the grid if required
5619  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
5620  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
5621  if(Track->GapsUnset(1))
5622  {
5623  SetGapsButton->Enabled = true;
5624  }
5625  // only enable if there are gaps still to be set (returns false for no track)
5626  else
5627  {
5628  if(!(Track->NoActiveTrack(0)) && !(Track->IsTrackFinished()))
5629  {
5630  TrackOKButton->Enabled = true;
5631  }
5632  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
5633  }
5634  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
5635  {
5636  SetLengthsButton->Enabled = false;
5637  }
5638  if(NoRailway())
5639  {
5640  EditMenu->Enabled = false;
5641  }
5642  else
5643  EditMenu->Enabled = true;
5644  }
5645  Screen->Cursor = TCursor(-2); // Arrow
5646  Utilities->CallLogPop(35);
5647  return;
5648  }
5649  else if(Level2TrackMode == DistanceContinuing) // new for extended distances (similar to PrefDirContinuing)
5650  {
5651  TrainController->LogEvent("mbRight + DistanceContinuing");
5653  bool LeadingPointsAtLastElement = false;
5654  if(ConstructPrefDir->GetPrefDirTruncateElement(0, HLoc, VLoc))
5655  {
5656  if(ConstructPrefDir->PrefDirSize() == 0)
5657  {
5659  SetLevel1Mode(64);
5661  SetLevel2TrackMode(51); // calls ClearandRebuildRailway to show length erased & sets back to start
5662  Utilities->CallLogPop(1526);
5663  return;
5664  }
5667  ConstructPrefDir->CalcDistanceAndSpeed(0, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
5668  if(!LeadingPointsAtLastElement)
5669  {
5670  TrackLengthPanel->Visible = true;
5671  TrackLengthPanel->SetFocus();
5672  InfoPanel->Visible = true;
5673  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
5674  RestoreAllDefaultLengthsButton->Enabled = true;
5675  ResetDefaultLengthButton->Enabled = true;
5676  LengthOKButton->Enabled = true;
5677  DistanceBox->Text = AnsiString(OverallDistance);
5678  if(OverallSpeedLimit > -1)
5679  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
5680  else
5681  SpeedLimitBox->Text = "Mixed";
5682  }
5683  else
5684  {
5685  TrackLengthPanel->Visible = true;
5686  TrackLengthPanel->SetFocus();
5687  InfoPanel->Visible = true;
5688  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, continue or truncate";
5689  RestoreAllDefaultLengthsButton->Enabled = false;
5690  ResetDefaultLengthButton->Enabled = false;
5691  LengthOKButton->Enabled = false;
5692  }
5694  }
5695  Utilities->CallLogPop(36);
5696  return;
5697  }
5698 
5699  else if(Level2PrefDirMode == PrefDirContinuing) // truncate
5700  {
5701  TrainController->LogEvent("mbRight + PrefDirContinuing");
5703 // RlyFile = false; - don't alter this just for PrefDir changes
5704  if(ConstructPrefDir->GetPrefDirTruncateElement(1, HLoc, VLoc))
5705  {
5706  if(ConstructPrefDir->PrefDirSize() == 0)
5707  {
5709  SetLevel1Mode(14); // all PrefDir truncated
5710  Utilities->CallLogPop(37);
5711  return;
5712  }
5714  }
5716  SetLevel2PrefDirMode(0); // calls ClearandRebuildRailway to show length erased & sets back to start
5717  Utilities->CallLogPop(38);
5718  return;
5719  }
5720 
5721  else if((Level1Mode == PrefDirMode) && (Level2PrefDirMode != PrefDirContinuing) && (Level2PrefDirMode != PrefDirSelecting)) // delete element
5722  {
5723  TrainController->LogEvent("mbRight + != PrefDirContinuing");
5725 // RlyFile = false; - don't alter this just for PrefDir changes
5728  SetLevel1Mode(15); // calls ClearandRebuildRailway to show length erased & sets back to start
5729  Utilities->CallLogPop(39);
5730  return;
5731  }
5732 
5733  else if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // disallow when paused, but allow some parts in prestart
5734  {
5735  TrainController->LogEvent("mbRight + OperMode");
5736  bool FoundFlag;
5737  int VecPos = Track->GetVectorPositionFromTrackMap(1, HLoc, VLoc, FoundFlag);
5738  if(FoundFlag && (Level2OperMode != PreStart)) // disallow signaller control in PreStart
5739  {
5741  // signaller control of train
5742  if(SelectedTrainID > -1)
5743  {
5746  if((Train.LeadElement == -1) || (Track->TrackElementAt(788, Train.LeadElement).Conn[Train.LeadExitPos] == -1))
5747  {
5748  if(Train.TrainMode == Signaller)
5749  {
5751  }
5752  }
5753  if((Train.Stopped()) || (Train.TrainFailed && !(Train.TrainMode == Signaller)) ||
5755  !Train.StepForwardFlag))
5756  // don't allow signaller popup menu in timetable mode unless stopped,
5757  // or when coming to a stop or leaving at a continuation when under signaller control
5758  // or when failed
5759  {
5760  // don't allow selection if another stopped train at a bridge position
5761  if(Track->TrackElementAt(630, VecPos).TrackType == Bridge)
5762  {
5763  int TrainID01 = Track->TrackElementAt(631, VecPos).TrainIDOnBridgeTrackPos01;
5764  int TrainID23 = Track->TrackElementAt(632, VecPos).TrainIDOnBridgeTrackPos23;
5765  if((TrainID01 > -1) && (TrainID23 > -1))
5766  {
5767  TrainController->StopTTClockMessage(0, "Can't select a train at a bridge when another train is at the same bridge");
5768  Utilities->CallLogPop(1103);
5769  return;
5770  }
5771  }
5772  if(Train.TrainMode == Timetable)
5773  {
5774  TakeSignallerControlMenuItem->Enabled = true;
5775  TimetableControlMenuItem->Enabled = false;
5776  ChangeDirectionMenuItem->Enabled = false;
5777  MoveForwardsMenuItem->Enabled = false;
5778  SignallerJoinedByMenuItem->Enabled = false;
5779  RepairFailedTrainMenuItem->Enabled = false;
5780  StepForwardMenuItem->Enabled = false;
5781  RemoveTrainMenuItem->Enabled = false;
5782  PassRedSignalMenuItem->Enabled = false;
5783  SignallerControlStopMenuItem->Enabled = false;
5784  }
5785  else // signaller mode
5786  {
5787  TakeSignallerControlMenuItem->Enabled = false;
5788  if((Train.Crashed) || (Train.Derailed))
5789  {
5790  TimetableControlMenuItem->Enabled = false;
5791  ChangeDirectionMenuItem->Enabled = false;
5792  MoveForwardsMenuItem->Enabled = false;
5793  SignallerJoinedByMenuItem->Enabled = false;
5794  RepairFailedTrainMenuItem->Enabled = false;
5795  StepForwardMenuItem->Enabled = false;
5796  PassRedSignalMenuItem->Enabled = false;
5797  SignallerControlStopMenuItem->Enabled = false;
5798  RemoveTrainMenuItem->Enabled = true;
5799  }
5800  else if(Train.Stopped())
5801  {
5802  if(Train.TimetableFinished)
5803  {
5804  TimetableControlMenuItem->Enabled = false;
5805  }
5806  else
5807  {
5808  if(Train.RestoreTimetableLocation == "") // en route
5809  {
5810  TimetableControlMenuItem->Enabled = true;
5811  }
5812  else
5813  {
5814  // obtain train location & check if OK for restoration of tt control
5815  AnsiString LocName = "";
5816  if(Train.LeadElement > -1)
5817  {
5818  LocName = Track->TrackElementAt(802, Train.LeadElement).ActiveTrackElementName;
5819  }
5820  if((LocName == "") && (Train.MidElement > -1))
5821  {
5822  LocName = Track->TrackElementAt(803, Train.MidElement).ActiveTrackElementName;
5823  }
5824  if(Train.RestoreTimetableLocation == LocName)
5825  {
5826  TimetableControlMenuItem->Enabled = true;
5827  }
5828  else
5829  {
5830  TimetableControlMenuItem->Enabled = false;
5831  }
5832  }
5833  }
5834 // don't allow ChangeDirection if lead or mid elements (but not lag or next) -1, or lead, mid, lag or next elements continuations
5835  ChangeDirectionMenuItem->Enabled = true;
5836  if(Train.LeadElement > -1)
5837  {
5839  {
5840  ChangeDirectionMenuItem->Enabled = false;
5841  }
5842  if(Track->TrackElementAt(791, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
5843  {
5844  if(Track->TrackElementAt(792, (Track->TrackElementAt(793, Train.LeadElement).Conn[Train.LeadExitPos]))
5845  .TrackType == Continuation)
5846  {
5847  ChangeDirectionMenuItem->Enabled = false;
5848  }
5849  }
5850  }
5851  else
5852  ChangeDirectionMenuItem->Enabled = false;
5853  if(Train.MidElement > -1)
5854  {
5856  {
5857  ChangeDirectionMenuItem->Enabled = false;
5858  }
5859  }
5860  else
5861  ChangeDirectionMenuItem->Enabled = false;
5862  if(Train.LagElement > -1)
5863  {
5865  {
5866  ChangeDirectionMenuItem->Enabled = false;
5867  }
5868  }
5869  RemoveTrainMenuItem->Enabled = true;
5870  SignallerControlStopMenuItem->Enabled = false;
5871  SignallerJoinedByMenuItem->Enabled = false;
5872  RepairFailedTrainMenuItem->Enabled = false;
5873  StepForwardMenuItem->Enabled = false;
5874  MoveForwardsMenuItem->Enabled = false;
5875  PassRedSignalMenuItem->Enabled = false;
5876  if(Train.AbleToMove(0))
5877  {
5878  MoveForwardsMenuItem->Enabled = true;
5880  StepForwardMenuItem->Enabled = true; // added 'if' condition for v1.3.2 due to Carwyn Thomas error,
5881  } // fails on trying to calc AutoSig time delay for resetting signals
5882  if(Train.AbleToMoveButForSignal(0)) // may not be in AutoSigs route but disallow anyway as not needed at continuation
5883  {
5884  PassRedSignalMenuItem->Enabled = true;
5885  StepForwardMenuItem->Enabled = true;
5886  }
5887  TTrain *AdjacentTrain;
5888  if(Train.IsThereAnAdjacentTrain(0, AdjacentTrain))
5889  {
5890  SignallerJoinedByMenuItem->Enabled = true;
5891  }
5892  if(Train.TrainFailed)
5893  {
5894  RepairFailedTrainMenuItem->Enabled = true;
5895  }
5896  }
5897  else // train moving under signaller control - only permit restoration of TT control when stopped as could be in
5898  // mid move, & SetTrainMovementValues only intended to be called when stopped
5899  {
5900  TimetableControlMenuItem->Enabled = false;
5901  ChangeDirectionMenuItem->Enabled = false;
5902  RemoveTrainMenuItem->Enabled = false;
5903  MoveForwardsMenuItem->Enabled = false;
5904  SignallerJoinedByMenuItem->Enabled = false;
5905  RepairFailedTrainMenuItem->Enabled = false;
5906  PassRedSignalMenuItem->Enabled = false;
5907  StepForwardMenuItem->Enabled = false;
5908  SignallerControlStopMenuItem->Enabled = true;
5909  }
5910  }
5911  TrainHeadCodeMenuItem->Caption = Train.HeadCode + ":";
5912  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
5914  PopupMenu->Popup(X, Y); // menu stops everything so reset timetable time when restarts
5915  TrainController->BaseTime = TDateTime::CurrentDateTime();
5917  Utilities->CallLogPop(40);
5918  return;
5919  }
5920  }
5921  }
5922 
5923  if(RouteMode == RouteContinuing) // clear a single element (clears whether use left or right mouse button) +allow in PreStart
5924  {
5925  TrainController->LogEvent("mbRight + RouteContinuing");
5927  Utilities->CallLogPop(41);
5928  return;
5929  }
5930 
5931  else if(RouteCancelFlag) // allow in PreStart
5932  {
5933  TrainController->LogEvent("mbRight + RouteCancelFlag");
5934  Screen->Cursor = TCursor(-11); // Hourglass;
5935  // stop clock as sometimes takes several seconds
5936  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
5938  if(AllRoutes->GetAllRoutesTruncateElement(0, HLoc, VLoc, ConsecSignalsRoute)) // updates LockedRouteClass
5939  {
5940  ClearandRebuildRailway(6); // to replot new shorter route
5941  }
5943  TrainController->BaseTime = TDateTime::CurrentDateTime();
5945  Screen->Cursor = TCursor(-2); // Arrow
5946  }
5947 
5948  else // gap flashing, don't allow to interfere with RouteCancelFlag
5949  {
5950  TrainController->LogEvent("mbRight, GapFlashingInOperOrPreStartMode");
5951  int Position;
5952  TTrackElement TrackElement;
5953  if(Track->FindNonPlatformMatch(4, HLoc, VLoc, Position, TrackElement));
5954  {
5955  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
5956  {
5957  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(818, TrackElement.Conn[0]).TrainIDOnElement == -1))
5958  { // don't flash if train on either gap element
5959  Track->GapFlashGreenPosition = TrackElement.Conn[0];
5964  Track->GapFlashRedPosition = Position;
5969  Track->GapFlashFlag = true;
5970  }
5971  }
5972  }
5973  Utilities->CallLogPop(42);
5974  return; // covers above else & included here in case any more usermodes added later
5975  }
5976  }
5977 
5978  // deal with gap selection - if no other right button selection - apply for any mode (also included in OperMode above)
5979  TrainController->LogEvent("mbRight, GapFlashingNotOperOrPreStartMode");
5980  int Position;
5981  TTrackElement TrackElement;
5982  if(Track->FindNonPlatformMatch(18, HLoc, VLoc, Position, TrackElement));
5983  {
5984  if((TrackElement.TrackType == GapJump) && (TrackElement.Conn[0] > -1))
5985  {
5986  if((TrackElement.TrainIDOnElement == -1) && (Track->TrackElementAt(819, TrackElement.Conn[0]).TrainIDOnElement == -1))
5987  { // don't flash if train on either gap element
5988  Track->GapFlashGreenPosition = TrackElement.Conn[0];
5992  Track->GapFlashRedPosition = Position;
5996  Track->GapFlashFlag = true;
5997  }
5998  }
5999  }
6000  Utilities->CallLogPop(67);
6001  return; // covers above else & included here in case any more usermodes added later
6002  }
6003 
6004 // Left Mouse Button Functions
6005  if(RouteCancelFlag)
6007  mbLeftDown = true;
6008 
6009  if(Level2TrackMode == AddTrack)
6010  {
6011  TrainController->LogEvent("mbLeft + AddTrack");
6012  Screen->Cursor = TCursor(-11); // Hourglass;
6014  bool TrackLinkingRequiredFlag;
6015  int CurrentTag;
6016  TSpeedButton *TempSpeedButton = 0;
6017  if(CurrentSpeedButton)
6018  {
6019  CurrentTag = CurrentSpeedButton->Tag;
6020  TempSpeedButton = CurrentSpeedButton;
6021  }
6022  else
6023  CurrentTag = 0;
6024  bool InternalChecks = true;
6025  Track->PlotAndAddTrackElement(1, CurrentTag, 0, HLoc, VLoc, TrackLinkingRequiredFlag, InternalChecks);
6026  // above now has extra zero 'Aspect' parameter at v2.2.0 so can distinguish between adding track and pasting
6027  EditMenu->Enabled = true;
6028  if(Track->NamedLocationElementAt(1, HLoc, VLoc))
6029  ClearandRebuildRailway(7); // so named location graphics plotted correctly
6030  if(TrackLinkingRequiredFlag)
6031  {
6032  Track->SetTrackFinished(false);
6033  }
6034  SetTrackBuildImages(10);
6035  SetGapsButton->Enabled = false; // if conditions have changed need to reset buttons, best not calling SetLevel2TrackMode as that
6036  TrackOKButton->Enabled = false; // calls Clearand.. if gridflag set & takes a long time
6037  if(Track->GapsUnset(2))
6038  {
6039  SetGapsButton->Enabled = true;
6040  }
6041  // only enable if there are gaps still to be set (returns false for no track)
6042  else
6043  {
6044  if(!(Track->NoActiveTrack(1)) && !(Track->IsTrackFinished()))
6045  {
6046  TrackOKButton->Enabled = true;
6047  }
6048  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
6049  }
6050  if(!(Track->IsTrackFinished())) // can only set lengths for several elements together if TrackFinished
6051  {
6052  SetLengthsButton->Enabled = false;
6053  }
6054  if(TempSpeedButton) // restore button if was pressed
6055  {
6056  CurrentSpeedButton = TempSpeedButton;
6057  CurrentSpeedButton->Down = true;
6058  }
6059  Screen->Cursor = TCursor(-2); // Arrow
6060  Utilities->CallLogPop(44);
6061  return;
6062  }
6063 
6064  else if(Level2TrackMode == AddGraphic)
6065  {
6066  TrainController->LogEvent("mbLeft + AddGraphic");
6067  ResetChangedFileDataAndCaption(24, false);
6068  TUserGraphicItem NewGI;
6069  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
6070  if(UGMIt != Track->UserGraphicMap.end()) // if it is the end then nothing was found
6071  {
6072  NewGI.UserGraphic = UGMIt->second;
6073  NewGI.Width = UGMIt->second->Width;
6074  NewGI.Height = UGMIt->second->Height;
6076  NewGI.HPos = X + (Display->DisplayOffsetH * 16);
6077  NewGI.VPos = Y + (Display->DisplayOffsetV * 16);
6078  Track->UserGraphicVector.push_back(NewGI);
6079  Display->PlotAndAddUserGraphic(1, NewGI);
6080  }
6081  else
6082  {
6083  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
6084  Utilities->CallLogPop(2195);
6085  return;
6086  }
6087  MoveTextOrGraphicButton->Enabled = true;
6088  EditMenu->Enabled = true;
6089  Utilities->CallLogPop(2182);
6090  return;
6091  }
6092 
6093  else if(Level2TrackMode == AddLocationName)
6094  {
6095  TrainController->LogEvent("mbLeft + AddLocationName");
6097  bool FoundFlag;
6098  TTrackElement TrackElement;
6099  AnsiString NameString;
6100  TTrack::TIMPair InactivePair = Track->GetVectorPositionsFromInactiveTrackMap(1, HLoc, VLoc, FoundFlag);
6101  if(!FoundFlag)
6102  {
6103  Utilities->CallLogPop(45);
6104  return; // inactive element not found (has to be a platform or named non-station location, can't select any other element)
6105  }
6106  TTrackElement& InactiveTrackElement1 = Track->InactiveTrackElementAt(28, InactivePair.first);
6107  TTrackElement& InactiveTrackElement2 = Track->InactiveTrackElementAt(29, InactivePair.second); // may be same element if only 1
6108  TTrackElement& ValidElement = InactiveTrackElement1;
6109  unsigned int ValidPosition;
6110  if((InactiveTrackElement1.TrackType != Platform) && (InactiveTrackElement2.TrackType != Platform) &&
6111  (InactiveTrackElement1.TrackType != NamedNonStationLocation) && (InactiveTrackElement2.TrackType != NamedNonStationLocation) &&
6112  (InactiveTrackElement1.TrackType != Concourse) && (InactiveTrackElement2.TrackType != Concourse))
6113  {
6114  Utilities->CallLogPop(46);
6115  return; // element not valid
6116  }
6117  if((InactiveTrackElement1.TrackType == Platform) || (InactiveTrackElement1.TrackType == NamedNonStationLocation) ||
6118  (InactiveTrackElement1.TrackType == Concourse))
6119  {
6120  ValidElement = InactiveTrackElement1;
6121  ValidPosition = InactivePair.first;
6122  }
6123  else if((InactiveTrackElement2.TrackType == Platform) || (InactiveTrackElement2.TrackType == NamedNonStationLocation) ||
6124  (InactiveTrackElement2.TrackType == Concourse))
6125  {
6126  ValidElement = InactiveTrackElement2;
6127  ValidPosition = InactivePair.second;
6128  }
6129  // now have required element as ValidElement & position in InactiveTrackvector as ValidPosition
6130 
6131  // put a square box round element to show selection
6132  Display->Rectangle(0, HLoc * 16, VLoc * 16, clB0G0R5, 0, 2);
6133  LocationNameTextBox->Visible = true;
6134  LocationNameTextBox->SetFocus();
6135  NameString = Track->GetLocationName(ValidPosition);
6136  LocationNameTextBox->Text = NameString;
6137  InfoPanel->Visible = true;
6138  InfoPanel->Caption = "NAMING LOCATIONS: Enter name, 'Carriage Return' to accept, 'Escape' to quit";
6139 
6140  Track->LNPendingList.clear();
6141  Track->LNPendingList.insert(Track->LNPendingList.end(), ValidPosition);
6142  Level2TrackMode = NoTrackMode; // if leave as AddLocationName can select other squares before enter name
6143  Utilities->CallLogPop(47);
6144  return;
6145  }
6146 
6147  else if(Level2TrackMode == DistanceStart) // new for extended distances - similar to !PrefDirContinuing
6148  // prior to selecting start element
6149  {
6150  TrainController->LogEvent("mbLeft + DistanceStart");
6152  if(ConstructPrefDir->GetPrefDirStartElement(0, HLoc, VLoc))
6153  {
6156  SetLevel1Mode(65);
6158  SetLevel2TrackMode(30);
6159  }
6160  Utilities->CallLogPop(48);
6161  return;
6162  }
6163 
6164  else if(Level2TrackMode == DistanceContinuing) // new for extended distances - similar to PrefDirContinuing
6165  // prior to selecting finish element
6166  {
6167  TrainController->LogEvent("mbLeft + DistanceContinuing");
6169  bool FinishElement = false, LeadingPointsAtLastElement = false;
6170  Screen->Cursor = TCursor(-11); // Hourglass;
6171  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(181, 0).HLoc != HLoc) ||
6172  (ConstructPrefDir->GetFixedPrefDirElementAt(182, 0).VLoc != VLoc))
6173  { // not same as start element
6174  if(ConstructPrefDir->GetNextPrefDirElement(0, HLoc, VLoc, FinishElement))
6175  {
6178  ConstructPrefDir->CalcDistanceAndSpeed(1, OverallDistance, OverallSpeedLimit, LeadingPointsAtLastElement);
6179  if(FinishElement)
6180  {
6181  TrackLengthPanel->Visible = true;
6182  TrackLengthPanel->SetFocus();
6183  InfoPanel->Visible = true;
6184  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values (overall length), or right click to cancel/truncate";
6185  RestoreAllDefaultLengthsButton->Enabled = true;
6186  ResetDefaultLengthButton->Enabled = true;
6187  LengthOKButton->Enabled = true;
6188  DistanceBox->Text = AnsiString(OverallDistance);
6189  if(OverallSpeedLimit > -1)
6190  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6191  else
6192  SpeedLimitBox->Text = "Mixed";
6194  Screen->Cursor = TCursor(-2); // Arrow
6195  Utilities->CallLogPop(1527);
6196  return;
6197  }
6198  else
6199  {
6200  if(!LeadingPointsAtLastElement)
6201  {
6202  TrackLengthPanel->Visible = true;
6203  TrackLengthPanel->SetFocus();
6204  InfoPanel->Visible = true;
6205  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
6206  RestoreAllDefaultLengthsButton->Enabled = true;
6207  ResetDefaultLengthButton->Enabled = true;
6208  LengthOKButton->Enabled = true;
6209  DistanceBox->Text = AnsiString(OverallDistance);
6210  if(OverallSpeedLimit > -1)
6211  SpeedLimitBox->Text = AnsiString(OverallSpeedLimit);
6212  else
6213  SpeedLimitBox->Text = "Mixed";
6214  // Level2TrackMode = DistanceContinuing;
6215  // SetLevel2TrackMode();
6216  }
6217  else
6218  {
6219  TrackLengthPanel->Visible = true;
6220  TrackLengthPanel->SetFocus();
6221  InfoPanel->Visible = true;
6222  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Can't end on leading points, need to continue or truncate";
6223  RestoreAllDefaultLengthsButton->Enabled = false;
6224  ResetDefaultLengthButton->Enabled = false;
6225  LengthOKButton->Enabled = false;
6226  // Level2TrackMode = DistanceContinuing;
6227  // SetLevel2TrackMode();
6228  }
6229  }
6230  }
6231  }
6232  else // same as start element
6233  {
6236  SetLevel2TrackMode(54);
6237  Screen->Cursor = TCursor(-2); // Arrow
6238  Utilities->CallLogPop(1713);
6239  return;
6240  }
6242  Screen->Cursor = TCursor(-2); // Arrow
6243  Utilities->CallLogPop(1490);
6244  return;
6245  }
6246 
6247  else if(Level2TrackMode == GapSetting)
6248  {
6249  TrainController->LogEvent("mbLeft + GapSetting");
6251  // HighLightOneGap already called once from SetLevel2TrackMode so have all gap element values set
6252  // & it is highlighted
6253  if(!(Track->FindSetAndDisplayMatchingGap(1, HLoc, VLoc)))
6254  {
6255  Utilities->CallLogPop(50);
6256  return; // true if finds one
6257  }
6258  InfoPanel->Visible = true;
6259  InfoPanel->Caption = "CONNECTING GAPS: Connecting element selected";
6260  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
6261  Delay(0, 500); // 500 msec delay before next selection requested
6262 
6263  // ClearandRebuildRailway(8);//get rid of gap selections
6264  // need to call this later when new gap displayed, else old gap remains
6265 
6266  // now back to highlighting next gap
6267  // bool LocError = false;
6268  if(!(HighLightOneGap(1, HLoc, VLoc)))
6269  {
6270  // all gaps set
6271  ShowMessage("All gaps set");
6272  if(Level2TrackMode == AddTrack)
6273  {
6275  SetLevel1Mode(66);
6276  SetLevel2TrackMode(31);
6277  }
6278  else
6279  {
6281  SetLevel1Mode(37);
6282  }
6283  ClearandRebuildRailway(9); // get rid of last gap ellipse
6284  Utilities->CallLogPop(51);
6285  return;
6286  }
6287  // here if one gap highlighted so return to user to allow corresponding gap to be selected
6288  // by another call to MainScreenMouseDown
6289  }
6290 
6291  else if(Level2TrackMode == AddText)
6292  {
6293  TrainController->LogEvent("mbLeft + AddText");
6295  // X & Y are relative to Display output, but TextBox is placed relative to Form
6296  // if mouse position on first character of an existing piece of text reload it into the editor
6297 
6298  bool TextFoundFlag = false;
6299  int TrueX = 0, TrueY = 0;
6300  AnsiString ExistingText = "";
6302  TFont *ExistingTextFont = new TFont;
6303  int ExistingTextHPos = 0, ExistingTextVPos = 0;
6304  Track->GetTruePositionsFromScreenPos(1, TrueX, TrueY, X, Y);
6305  if(!TextHandler->TextVector.empty())
6306  {
6307  for(TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin(); TextPtr--)
6308  {
6309  if((TrueX >= TextPtr->HPos) && (TrueX < (TextPtr->HPos + abs(TextPtr->Font->Height))) && (TrueY >= TextPtr->VPos) && (TrueY <
6310  (TextPtr->VPos + abs(TextPtr->Font->Height))))
6311  {
6312  ExistingText = TextPtr->TextString;
6313  ExistingTextFont->Assign(TextPtr->Font);
6314  ExistingTextHPos = TextPtr->HPos;
6315  ExistingTextVPos = TextPtr->VPos;
6316  TextFoundFlag = true;
6317  TextHandler->TextErase(9, TrueX, TrueY, ExistingText);
6318  break;
6319  } // if ....
6320  } // for TextPtr...
6321  } // if !TextVector...
6322 
6323  if(TextFoundFlag)
6324  {
6325  TextBox->Left = ExistingTextHPos + Display->Left() - (Display->DisplayOffsetH * 16) - 3;
6326  TextBox->Top = ExistingTextVPos + Display->Top() - (Display->DisplayOffsetV * 16) - 3;
6327  TextBox->Font->Assign(ExistingTextFont);
6328  Display->SetFont(ExistingTextFont);
6329  Text_X = ExistingTextHPos;
6330  Text_Y = ExistingTextVPos;
6331  }
6332  else
6333  {
6334  TextBox->Left = (TextOrUserGraphicGridVal * div((Display->Left() + X), TextOrUserGraphicGridVal).quot) - 3;
6335  TextBox->Top = (TextOrUserGraphicGridVal * div((Display->Top() + Y), TextOrUserGraphicGridVal).quot) - 3;
6336  TextBox->Font->Assign(Display->GetFont());
6337  Text_X = TextOrUserGraphicGridVal * div(NoOffsetX, TextOrUserGraphicGridVal).quot;
6338  Text_Y = TextOrUserGraphicGridVal * div(NoOffsetY, TextOrUserGraphicGridVal).quot;
6339  }
6340  TextBox->Visible = true;
6341  TextBox->SetFocus();
6342  if(TextFoundFlag)
6343  TextBox->Text = ExistingText;
6344  else
6345  TextBox->Text = "New Text: CR=end, ESC=quit";
6346  TextBox->Width = (abs(TextBox->Font->Height) * TextBox->Text.Length() * 0.7);
6347  TextBox->SelectAll();
6348  delete ExistingTextFont;
6349  ClearandRebuildRailway(29); // to remove old text if replaced
6351  Utilities->CallLogPop(1775);
6352  return; // If text input go no further
6353  }
6354 
6356  {
6357  TrainController->LogEvent("mbLeft + MoveTextOrGraphic");
6359  // int HPosInput;// = X + (Display->DisplayOffsetH * 16);
6360  // int VPosInput;// = Y + (Display->DisplayOffsetV * 16);
6361  // Track->GetTruePositionsFromScreenPos(HPosInput, VPosInput, X, Y);
6362  // StartX = X + (Display->DisplayOffsetH * 16);
6363  // StartY = Y + (Display->DisplayOffsetV * 16);
6366  if(!TextFoundFlag) // give precedence to text
6367  {
6369  }
6370  Utilities->CallLogPop(53);
6371  return; // if text move selected don't permit anything else
6372  }
6373 
6374  else if(Level2TrackMode == TrackSelecting)
6375 /* When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
6376  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
6377  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
6378  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
6379  selected rectangle.
6380 */
6381  {
6382  TrainController->LogEvent("mbLeft + TrackSelecting");
6383  ClearandRebuildRailway(10); // to get rid of earlier rectangles
6384  SelectStartPair.first = HLoc;
6385  SelectStartPair.second = VLoc;
6386  }
6387 
6388  else if((Level2TrackMode == CopyMoving) || (Level2TrackMode == CutMoving))
6389 /* The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
6390  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
6391  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
6392  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
6393 */
6394  {
6395  TrainController->LogEvent("mbLeft + CopyMoving or CutMoving");
6397  if((X < ((SelectBitmapHLoc - Display->DisplayOffsetH) * 16) + 4) ||
6398  (X > ((SelectBitmapHLoc + (SelectBitmap->Width / 16) - Display->DisplayOffsetH) * 16) - 4))
6399  {
6400  SelectPickedUp = false;
6401  Utilities->CallLogPop(54);
6402  return; // within 4 pixels of outside of horizontal area (4 pixels are so can't push selection off edge of screen)
6403  }
6404  if((Y < ((SelectBitmapVLoc - Display->DisplayOffsetV) * 16) + 4) ||
6405  (Y > ((SelectBitmapVLoc + (SelectBitmap->Height / 16) - Display->DisplayOffsetV) * 16) - 4))
6406  {
6407  SelectPickedUp = false;
6408  Utilities->CallLogPop(55);
6409  return; // within 4 pixels of outside of vertical area (4 pixels are so can't push selection off edge of screen)
6410  }
6411  else
6412  {
6413  SelectPickedUp = true;
6414  }
6417  }
6418 
6420  {
6421  TrainController->LogEvent("mbLeft + != PrefDirContinuing");
6422  ResetChangedFileDataAndCaption(15, false);
6423 // RlyFile = false; - don't alter this just for PrefDir changes
6424  if(ConstructPrefDir->GetPrefDirStartElement(1, HLoc, VLoc))
6425  {
6429  }
6430  Utilities->CallLogPop(56);
6431  return;
6432  }
6433 
6435  {
6436  TrainController->LogEvent("mbLeft + PrefDirContinuing");
6437  ResetChangedFileDataAndCaption(16, false);
6438 // RlyFile = false; - don't alter this just for PrefDir changes
6439  bool FinishElement;
6440  Screen->Cursor = TCursor(-11); // Hourglass;
6441  if((ConstructPrefDir->PrefDirSize() != 1) || (ConstructPrefDir->GetFixedPrefDirElementAt(183, 0).HLoc != HLoc) ||
6442  (ConstructPrefDir->GetFixedPrefDirElementAt(184, 0).VLoc != VLoc))
6443  { // not same as start element
6444  if(ConstructPrefDir->GetNextPrefDirElement(1, HLoc, VLoc, FinishElement))
6445  {
6447  if(FinishElement)
6448  {
6449  ShowMessage("Preferred direction added");
6452  SetLevel1Mode(16);
6453  Screen->Cursor = TCursor(-2); // Arrow
6454  Utilities->CallLogPop(57);
6455  return;
6456  }
6457  else
6458  {
6461  }
6462  // set again since 1st time
6463  // PrefDir vector only had start element & Truncate wasn't enabled, also need
6464  // to do the checks for Loop & End for each element as it is added
6465  }
6466  }
6467  else // same as start element
6468  {
6471  SetLevel1Mode(121);
6472  Screen->Cursor = TCursor(-2); // Arrow
6473  Utilities->CallLogPop(1714);
6474  return;
6475  }
6476  Screen->Cursor = TCursor(-2); // Arrow
6477  Utilities->CallLogPop(58);
6478  return;
6479  }
6480 
6482  {
6483  TrainController->LogEvent("mbLeft + PrefDirSelecting");
6484  ClearandRebuildRailway(56); // to get rid of earlier rectangles
6485  SelectStartPair.first = HLoc;
6486  SelectStartPair.second = VLoc;
6487  }
6488 
6489  else if(Level1Mode == OperMode)
6490  {
6491  if((Level2OperMode == Operating) && CallingOnButton->Down && CallingOnButton->Enabled)
6492  {
6493  TrainController->LogEvent("mbLeft + Operating & CallingOnButton->Down");
6494  int Position;
6495  TTrackElement TrackElement;
6496  if(Track->FindNonPlatformMatch(2, HLoc, VLoc, Position, TrackElement))
6497  {
6498  if(TrackElement.TrackType != SignalPost)
6499  {
6500  CallingOnButton->Down = false;
6501 // InfoPanel->Visible = false; //dropped at v1.3.0, not sure what purpose intended to serve but don't want to lose the info panel as did with this here also added line below to reset
6503  Utilities->CallLogPop(59);
6504  return;
6505  }
6506  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
6507  {
6509  {
6511  x).LeadExitPos] == Position) && (TrackElement.Config[Track->TrackElementAt(429, TrainController->TrainVectorAt(28,
6513  {
6514  // found it!
6515 /*
6516  if(TrackElement.SpeedTag == 68)
6517  {
6518  Display->PlotOutput(0, (HLoc * 16), (VLoc * 16), RailGraphics->bm68CallingOn);
6519  }
6520  if(TrackElement.SpeedTag == 69)
6521  {
6522  Display->PlotOutput(1, (HLoc * 16), (VLoc * 16), RailGraphics->bm69CallingOn);
6523  }
6524  if(TrackElement.SpeedTag == 70)
6525  {
6526  Display->PlotOutput(2, (HLoc * 16), (VLoc * 16), RailGraphics->bm70CallingOn);
6527  }
6528  if(TrackElement.SpeedTag == 71)
6529  {
6530  Display->PlotOutput(3, (HLoc * 16), (VLoc * 16), RailGraphics->bm71CallingOn);
6531  }
6532  if(TrackElement.SpeedTag == 72)
6533  {
6534  Display->PlotOutput(4, (HLoc * 16), (VLoc * 16), RailGraphics->bm72CallingOn);
6535  }
6536  if(TrackElement.SpeedTag == 73)
6537  {
6538  Display->PlotOutput(5, (HLoc * 16), (VLoc * 16), RailGraphics->bm73CallingOn);
6539  }
6540  if(TrackElement.SpeedTag == 74)
6541  {
6542  Display->PlotOutput(6, (HLoc * 16), (VLoc * 16), RailGraphics->bm74CallingOn);
6543  }
6544  if(TrackElement.SpeedTag == 75)
6545  {
6546  Display->PlotOutput(7, (HLoc * 16), (VLoc * 16), RailGraphics->bm75CallingOn);
6547  }
6548 */
6549  Track->TrackElementAt(430, Position).CallingOnSet = true;
6550  Track->PlotSignal(13, Track->TrackElementAt(893, Position), Display);
6551 // added at v 1.3.0 in place of the above to ensure ground signals (as well as others) plot correctly for proceed
6552  // have to call after CallingOnSet becomes true & can't use TrackElement as that still has CallingOnSet false
6553  ClearandRebuildRailway(69); // added at v1.3.0 to replot route on element after PlotSignal above
6556  CallingOnButton->Down = false;
6558 
6559 // set an unrestricted route into the station (just to the first platform) from the stop signal (note that it may be last in an autosigs
6560 // route) but remove any single route elements first (can't reach here if constructing a route), else may try to extend a route that
6561 // has been removed (only a precaution, shouldn't cause any probs whether single route set or not)
6562  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
6563  {
6564  if(AllRoutes->GetFixedRouteAt(192, x).PrefDirSize() == 1)
6565  {
6566  // only allow route element to be removed if not selected for a route start otherwise
6567  // StartSelectionRouteID will be set & will fail at convert
6569  {
6571  AllRoutes->RemoveRouteElement(21, PDE.HLoc, PDE.VLoc, PDE.GetELink());
6572  TrainController->LogEvent("SingleRouteElementRemovedDuringCallon, H = " + AnsiString(PDE.HLoc) + ", V = " +
6573  AnsiString(PDE.VLoc));
6574  }
6575  }
6576  }
6577 
6578 // find the correct entry in CallonVector - i.e. where Position == RouteStartEntry
6579  for(unsigned int x = 0; x < AllRoutes->CallonVector.size(); x++)
6580  {
6581  if(AllRoutes->CallonVector.at(x).RouteStartPosition == Position)
6582  { // found it
6583  if(!(AllRoutes->CallonVector.at(x).RouteOrPartRouteSet))
6584  // if RouteOrPartRouteSet false then set an unrestricted route into platform
6585  {
6586  bool PointsChanged = false;
6587  IDInt ReqPosRouteID(-1);
6588  TOneRoute *NewRoute = new TOneRoute;
6589  bool CallonTrue = true;
6590  bool ConsecSignalsRouteFalse = false;
6591  if(NewRoute->GetNonPreferredRouteStartElement(1,
6592  Track->TrackElementAt(841, AllRoutes->CallonVector.at(x).RouteStartPosition).HLoc,
6593  Track->TrackElementAt(842, AllRoutes->CallonVector.at(x).RouteStartPosition).VLoc, ConsecSignalsRouteFalse,
6594  CallonTrue))
6595  {
6596  if(NewRoute->GetNextNonPreferredRouteElement(1,
6597  Track->TrackElementAt(843, AllRoutes->CallonVector.at(x).PlatformPosition).HLoc,
6598  Track->TrackElementAt(844, AllRoutes->CallonVector.at(x).PlatformPosition).VLoc, ConsecSignalsRouteFalse,
6599  CallonTrue, ReqPosRouteID, PointsChanged))
6600  {
6601  if(!PointsChanged) // shouldn't be changed, something wrong if true so don't plot route
6602  {
6603  NewRoute->ConvertAndAddNonPreferredRouteSearchVector(3, ReqPosRouteID);
6604  ClearandRebuildRailway(67); // to plot the route (only finds one so won't call repeatedly)
6605  }
6606  }
6607  }
6608  delete NewRoute;
6609  }
6610  }
6611  }
6612 // InfoPanel->Visible = false;
6613  Utilities->CallLogPop(60);
6614  return;
6615  }
6616  }
6617  }
6618  }
6619  CallingOnButton->Down = false;
6621  Utilities->CallLogPop(61);
6622  return;
6623  }
6624 /* get 1st element, first check if selected points, not in existing route, & in RouteNotStarted mode
6625  if so, set all the flash values, Track->PointFlashFlag & start time, then exit for flasher to take over.
6626  If any of above conditions not met then treat as route selection, setting route flasher if
6627  route continuing.
6628 */
6629 
6630  if((Level2OperMode == Operating) || (Level2OperMode == PreStart)) // not 'else if' as both may apply
6631  // disallow route setting if paused
6632  {
6633  if(Level2OperMode == PreStart)
6634  {
6635  PointsFlashDuration = 0.0;
6638  }
6639  else
6640  {
6641  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
6642  if(TTClockSpeed < 1)
6643  TempSpeedVal = TTClockSpeed;
6644  PointsFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
6647  }
6648  if(RouteMode == RouteNotStarted)
6649  {
6650  TrainController->LogEvent("mbLeft + RouteNotStarted");
6651  int Position;
6652  TTrackElement TrackElement;
6653  if(Track->FindNonPlatformMatch(3, HLoc, VLoc, Position, TrackElement))
6654  {
6655  if((TrackElement.TrackType == Points) && !(AllRoutes->TrackIsInARoute(1, Position, 0))
6657  // Flash selected points & changeover if appropriate
6658  // need !Track->PointFlashFlag to prevent another point being selected while another is flashing, & !Track->RouteFlashFlag
6659  // to ensure user only does one thing at a time
6660  {
6661  if(TrackElement.TrainIDOnElement > -1)
6662  {
6663  TrainController->StopTTClockMessage(1, "Can't change points under a train!");
6664  Utilities->CallLogPop(62);
6665  return;
6666  }
6667  PointFlash->SetScreenHVSource(1, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6668 
6669 /*
6670  This used to try to allow any linked trailing edges to cause both points to change, but no good if
6671  there are two adjacent crossovers, where both trailing edges are linked to two different points.
6672  The wrong link might be chosen. Also doubtful if applying a strict order of checks would work, since
6673  may be obscure configurations that would be wrong. This function bypasses the MatchingPoint check, which
6674  ensures that there are no obscure links. Hence better to stick with original.
6675 
6676  //check if trailing edge linked to another point trailing edge
6677  int DivergingPosition = TrackElement.Conn[1];
6678  TTrackElement DivergingElement = Track->TrackElementAt(431, TrackElement.Conn[1]);
6679  DivergingPointVectorPosition = -1;
6680  if((DivergingElement.TrackType == Points) &&
6681  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
6682  {
6683  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
6684  {
6685  ShowMessage("Linked points Locked");
6686  }
6687  else DivergingPointVectorPosition = DivergingPosition;
6688  }
6689  else
6690  {
6691  DivergingPosition = TrackElement.Conn[3];
6692  DivergingElement = Track->TrackElementAt(432, TrackElement.Conn[3]);
6693  if((DivergingElement.TrackType == Points) &&
6694  ((DivergingElement.Conn[1] == Position) || (DivergingElement.Conn[3] == Position)))
6695  {
6696  if(AllRoutes->TrackIsInARoute(, DivergingPosition))
6697  {
6698  ShowMessage("Linked points locked");
6699  }
6700  else DivergingPointVectorPosition = DivergingPosition;
6701  }
6702  }
6703  Track->PointFlashFlag = true;
6704  PointFlashVectorPosition = Position;
6705  PointFlashStartTime = TrainController->TTClockTime;
6706  [close curly bracket - if include it matches earlier non-commented one!]
6707 */
6708  TTrackElement DivergingElement = Track->TrackElementAt(433, TrackElement.Conn[3]);
6709  int DivergingPosition = TrackElement.Conn[3];
6710  if((DivergingElement.TrackType == Points) && (DivergingElement.Conn[3] == Position) && (Track->MatchingPoint(1, Position,
6711  DivergingPosition))) // full match inc same attributes
6712  {
6713  if(AllRoutes->TrackIsInARoute(4, DivergingPosition, 0))
6714  {
6715  TrainController->StopTTClockMessage(2, "Linked points locked");
6716  }
6717  else
6718  {
6719  Track->PointFlashFlag = true;
6720  PointFlashVectorPosition = Position;
6721  DivergingPointVectorPosition = DivergingPosition;
6723  }
6724  }
6725  else // no matching point, just change this point
6726  {
6727  Track->PointFlashFlag = true;
6728  PointFlashVectorPosition = Position;
6731  }
6732  }
6733 /* drop manual changing of level crossings - only allow changing by setting a route through them
6734  else if((Track->IsLCAtHV(23, HLoc, VLoc) && !Track->PointFlashFlag && !Track->RouteFlashFlag))//level crossing
6735  {
6736  TTrack::TFlashLevelCrossing FLC;
6737  FLC.LCHLoc = HLoc;
6738  FLC.LCVLoc = VLoc;
6739  FLC.LCChangeStartTime = TrainController->TTClockTime;
6740  FLC.LCBaseElementSpeedTag = TrackElement.SpeedTag;
6741  if(Track->IsLCBarrierDownAtHV(0, HLoc, VLoc))
6742  {
6743  FLC.LCChangeDuration = LevelCrossingBarrierUpFlashDuration;
6744  FLC.BarrierState = TTrack::Raising;
6745  }
6746  else
6747  {
6748  FLC.LCChangeDuration = LevelCrossingBarrierDownFlashDuration;
6749  FLC.BarrierState = TTrack::Lowering;
6750  }
6751  Track->SetLinkedLevelCrossingBarrierAttributes(, HLoc, VLoc, 2);//set attr to 2 for changing state
6752  Track->ChangingLCVector.push_back(FLC);
6753  }
6754 */ else // route start
6755  {
6756  if(AutoSigsFlag)
6757  {
6758  AutoRouteStartMarker->SetScreenHVSource(2, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6760  }
6761  else if(ConsecSignalsRoute)
6762  {
6763  SigRouteStartMarker->SetScreenHVSource(3, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6765  }
6766  else
6767  {
6768  NonSigRouteStartMarker->SetScreenHVSource(4, TrackElement.HLoc * 16, TrackElement.VLoc * 16);
6770  }
6771  if(PreferredRoute)
6772  {
6773  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
6774  // another route building
6775  {
6776  ConstructRoute->ClearRoute(); // in case not empty though should be
6778  {
6779  if(AutoSigsFlag)
6781  else
6784  InfoPanel->Visible = true;
6785  if(Level2OperMode == PreStart)
6786  InfoPanel->Caption = "PRE-START: Select next route location";
6787  else
6788  InfoPanel->Caption = "OPERATING: Select next route location";
6789  }
6790  }
6791  Utilities->CallLogPop(63);
6792  return;
6793  }
6794  else // nonpreferred route
6795  {
6796  if(!Track->PointFlashFlag && !Track->RouteFlashFlag) // don't allow a route to start if a point changing or
6797  // another route building
6798  {
6799  ConstructRoute->ClearRoute(); // in case not empty though should be
6800  bool CallonFalse = false;
6801  if(ConstructRoute->GetNonPreferredRouteStartElement(0, HLoc, VLoc, ConsecSignalsRoute, CallonFalse))
6802  {
6805  InfoPanel->Visible = true;
6806  if(Level2OperMode == PreStart)
6807  InfoPanel->Caption = "PRE-START: Select next route location";
6808  else
6809  InfoPanel->Caption = "OPERATING: Select next route location";
6810  }
6811  }
6812  Utilities->CallLogPop(64);
6813  return;
6814  } // NonPreferred route
6815  } // TrackType != Points
6816  } // if(Track->FindNonPlatformMatch(HLoc, VLoc, Position, TrackElement))
6817  } // if(RouteMode == RouteNotStarted)
6818  else // RouteContinuing
6819  {
6820  TrainController->LogEvent("mbLeft + RouteContinuing");
6821  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
6824  AutoRouteStartMarker->PlotOriginal(14, Display); // if overlay not plotted will ignore
6825  SigRouteStartMarker->PlotOriginal(15, Display); // if overlay not plotted will ignore
6826  NonSigRouteStartMarker->PlotOriginal(16, Display); // if overlay not plotted will ignore
6827  Screen->Cursor = TCursor(-11); // Hourglass - also set to an hourglass when flashing, after found required
6828  // element, but this sets it to an hourglass while searching
6829  bool PointsChanged = false;
6830  if(PreferredRoute)
6831  {
6832  // route added to AllRoutes in GetNextRouteElement if valid
6833  // int ReqPosRouteNumber;
6835  ConstructRoute->ReqPosRouteID, PointsChanged))
6836  {
6837  Track->RouteFlashFlag = true;
6838  PreferredRouteFlag = true;
6839  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
6840  if(TTClockSpeed < 1)
6841  TempSpeedVal = TTClockSpeed;
6842  if(Level2OperMode == PreStart)
6843  RouteFlashDuration = 0.0;
6844  else if(PointsChanged)
6845  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
6846  else
6847  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
6848  ConstructRoute->SetRouteFlashValues(1, AutoSigsFlag, true); // true for ConsecSignalsRoute
6850  }
6851  else
6852  {
6854  }
6855  Screen->Cursor = TCursor(-2); // Arrow
6856  TrainController->BaseTime = TDateTime::CurrentDateTime();
6858  Utilities->CallLogPop(65);
6859  return;
6860  }
6861  else
6862  {
6863  bool CallonFalse = false;
6865  PointsChanged))
6866  {
6867  Track->RouteFlashFlag = true;
6868  PreferredRouteFlag = false;
6869  float TempSpeedVal = 1; // added for v2.3.0 to keep durations same as x1 values for slow speeds
6870  if(TTClockSpeed < 1)
6871  TempSpeedVal = TTClockSpeed;
6872  if(Level2OperMode == PreStart)
6873  RouteFlashDuration = 0.0;
6874  else if(PointsChanged)
6875  RouteFlashDuration = AllRoutes->PointsDelay * TempSpeedVal;
6876  else
6877  RouteFlashDuration = AllRoutes->SignalsDelay * TempSpeedVal;
6878  ConstructRoute->SetRouteFlashValues(2, false, false);
6880  }
6881  else
6882  {
6884  }
6885  }
6886  TrainController->BaseTime = TDateTime::CurrentDateTime();
6888  Screen->Cursor = TCursor(-2); // Arrow
6889  }
6890  Utilities->CallLogPop(66);
6891  return;
6892  }
6893  }
6894 
6895  Utilities->CallLogPop(68);
6896  }
6897  catch(const Exception &e)
6898  {
6899  ErrorLog(20, e.Message);
6900  }
6901 }
6902 
6903 // ---------------------------------------------------------------------------
6904 
6905 void TInterface::MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
6906  // ZoomOut mode
6907 {
6908 // NB: DisplayZoomOutOffsetH & V take account of the Min & Max H & V values so don't need these again
6909  try
6910  {
6911  TrainController->LogEvent("MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
6912  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MainScreenMouseDown3," + AnsiString(Button) + "," + AnsiString(X) +
6913  "," + AnsiString(Y));
6914  if(Button != mbLeft)
6915  {
6916  // this routine new at v2.1.0. Allows railway moving for zoom-out mode
6919  WholeRailwayMoving = true;
6920  Screen->Cursor = TCursor(-22); // Four arrows;
6921  }
6922  else
6923  {
6924  InfoPanel->Visible = false; // reset infopanel in case not set later
6925  InfoPanel->Caption = "";
6926  int HRounding, VRounding;
6927  int TruePosH = (X / 4) + Display->DisplayZoomOutOffsetH;
6928  int TruePosV = (Y / 4) + Display->DisplayZoomOutOffsetV;
6929  // find nearest screen centre - from 30 to 210 horiz & from 18 to 126 vert
6930  if(TruePosH < 0)
6931  HRounding = -(Utilities->ScreenElementWidth / 4);
6932  else
6933  HRounding = (Utilities->ScreenElementWidth / 4);
6934  int CentreH = (((TruePosH + HRounding) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2));
6935  while((CentreH - Track->GetHLocMax()) >= (Utilities->ScreenElementWidth / 2))
6936  CentreH -= (Utilities->ScreenElementWidth / 2);
6937  while((Track->GetHLocMin() - CentreH) >= (Utilities->ScreenElementWidth / 2))
6938  CentreH += (Utilities->ScreenElementWidth / 2);
6939  if(TruePosV < 0)
6940  VRounding = -(Utilities->ScreenElementHeight / 4);
6941  else
6942  VRounding = (Utilities->ScreenElementHeight / 4);
6943  int CentreV = (((TruePosV + VRounding) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2));
6944  while((CentreV - Track->GetVLocMax()) >= (Utilities->ScreenElementHeight / 2))
6945  CentreV -= (Utilities->ScreenElementHeight / 2);
6946  while((Track->GetVLocMin() - CentreV) >= (Utilities->ScreenElementHeight / 2))
6947  CentreV += (Utilities->ScreenElementHeight / 2);
6948  Display->DisplayOffsetH = CentreH - (Utilities->ScreenElementWidth / 2);
6950 
6951  TLevel2OperMode TempLevel2OperMode = Level2OperMode;
6952  if(Level1Mode == BaseMode)
6953  SetLevel1Mode(17);
6954  else if(Level1Mode == TrackMode)
6955  {
6956  // set edit menu items
6958  PreventGapOffsetResetting = true; // when return from zoom by clicking screen don't force a return to the
6959  // displayed gap, user wants to display the clicked area
6960  SetLevel2TrackMode(32); // revert to earlier track mode from zoom
6961  PreventGapOffsetResetting = false;
6962  }
6963  else if(Level1Mode == PrefDirMode)
6964  {
6966  SetLevel2PrefDirMode(3); // revert to earlier PrefDir mode from zoom
6967  else
6968  SetLevel1Mode(33); // if PrefDirSelecting revert to normap PrefDirMode
6969  }
6970  // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
6971  // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
6972  else if(Level1Mode == TimetableMode)
6973  {
6974  InfoPanel->Visible = false;
6975  }
6976  // Not OperMode or RestartSessionOperMode as that resets the performance file
6977  else if(TempLevel2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
6978  {
6979  OperateButton->Enabled = true;
6980  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
6981  ExitOperationButton->Enabled = true;
6983  }
6984  else if(TempLevel2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
6985  {
6986  OperateButton->Enabled = true;
6987  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
6988  ExitOperationButton->Enabled = true;
6989  TTClockAdjButton->Enabled = true;
6992  }
6993  else if(TempLevel2OperMode == PreStart)
6994  {
6995  OperateButton->Enabled = true;
6996  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
6997  ExitOperationButton->Enabled = true;
6998  TTClockAdjButton->Enabled = true;
7000  }
7001  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
7004  }
7005  Utilities->CallLogPop(69);
7006  }
7007  catch(const Exception &e)
7008  {
7009  ErrorLog(21, e.Message);
7010  }
7011 }
7012 
7013 // ---------------------------------------------------------------------------
7014 
7015 void __fastcall TInterface::MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
7016 {
7017  try
7018  {
7019  // TrainController->LogEvent("MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y)); //dropped at v0.6, too many events
7020  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseMove," + AnsiString(X) + "," + AnsiString(Y));
7021 
7022  if(!mbLeftDown && WholeRailwayMoving) // new at v2.1.0
7023  {
7024  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7026  if(X < 0)
7027  X = 0; // ensure pointer stays within display area
7028  if(X > (MainScreen->Width - 1))
7029  X = MainScreen->Width - 1;
7030  if(Y < 0)
7031  Y = 0;
7032  if(Y > (MainScreen->Height - 1))
7033  Y = MainScreen->Height - 1;
7034 
7035  if(!Display->ZoomOutFlag)
7036  {
7037  int StartOffsetX = (X - StartWholeRailwayMoveHPos) % 16;
7038  int StartOffsetY = (Y - StartWholeRailwayMoveVPos) % 16;
7039  if((abs(X - StartWholeRailwayMoveHPos) >= 16) || (abs(Y - StartWholeRailwayMoveVPos) >= 16))
7040  {
7041  int NewH = X - StartWholeRailwayMoveHPos;
7042  int NewV = Y - StartWholeRailwayMoveVPos;
7043  Display->DisplayOffsetH -= NewH / 16;
7044  Display->DisplayOffsetV -= NewV / 16;
7045  StartWholeRailwayMoveHPos = X - StartOffsetX;
7046  StartWholeRailwayMoveVPos = Y - StartOffsetY;
7049  {
7051  }
7052  }
7053  }
7054 
7055  else
7056  {
7057  int StartZOffsetX = (X - StartWholeRailwayMoveHPos) % 4;
7058  int StartZOffsetY = (Y - StartWholeRailwayMoveVPos) % 4;
7059  if((abs(X - StartWholeRailwayMoveHPos) >= 4) || (abs(Y - StartWholeRailwayMoveVPos) >= 4))
7060  {
7061  int NewH = X - StartWholeRailwayMoveHPos;
7062  int NewV = Y - StartWholeRailwayMoveVPos;
7063  Display->DisplayZoomOutOffsetH -= NewH / 4;
7064  Display->DisplayZoomOutOffsetV -= NewV / 4;
7065  StartWholeRailwayMoveHPos = X - StartZOffsetX;
7066  StartWholeRailwayMoveVPos = Y - StartZOffsetY;
7067  Display->ClearDisplay(10);
7069  }
7070  }
7071  TrainController->BaseTime = TDateTime::CurrentDateTime();
7073  }
7074 
7075  else if(mbLeftDown)
7076  {
7078 /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7079  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7080  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7081  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7082  selected rectangle.
7083  [New] At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7084  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7085  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7086  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7087  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7088  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7089  the selection.
7090 */
7091  {
7092  TrainController->LogEvent("MouseMove + TrackSelecting");
7093  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7094  Track->GetTrackLocsFromScreenPos(2, CurrentHLoc, CurrentVLoc, X, Y);
7095  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7096  // rightmost point and the VLoc value of the bottommost point
7097  if(CurrentHLoc >= StartHLoc)
7098  CurrentHLoc++;
7099  else
7100  StartHLoc++;
7101  if(CurrentVLoc >= StartVLoc)
7102  CurrentVLoc++;
7103  else
7104  StartVLoc++;
7105  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7107  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7109  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7110  CurrentHLoc = Display->DisplayOffsetH;
7111  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7112  CurrentVLoc = Display->DisplayOffsetV;
7113  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7114  ClearandRebuildRailway(14); // to clear earlier rectangles
7115  Display->PlotDashedRect(0, TempRect);
7116  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
7117  }
7118 
7120  {
7121  TrainController->LogEvent("MouseMove + PrefDirSelecting");
7122 
7123  int CurrentHLoc, CurrentVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7124  Track->GetTrackLocsFromScreenPos(5, CurrentHLoc, CurrentVLoc, X, Y);
7125  // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7126  // rightmost point and the VLoc value of the bottommost point
7127  if(CurrentHLoc >= StartHLoc)
7128  CurrentHLoc++;
7129  else
7130  StartHLoc++;
7131  if(CurrentVLoc >= StartVLoc)
7132  CurrentVLoc++;
7133  else
7134  StartVLoc++;
7135  if(CurrentHLoc - Display->DisplayOffsetH > Utilities->ScreenElementWidth)
7137  if(CurrentVLoc - Display->DisplayOffsetV > Utilities->ScreenElementHeight)
7139  if(CurrentHLoc - Display->DisplayOffsetH < 0)
7140  CurrentHLoc = Display->DisplayOffsetH;
7141  if(CurrentVLoc - Display->DisplayOffsetV < 0)
7142  CurrentVLoc = Display->DisplayOffsetV;
7143  TRect TempRect(StartHLoc, StartVLoc, CurrentHLoc, CurrentVLoc);
7144  ClearandRebuildRailway(57); // to clear earlier rectangles
7145  Display->PlotDashedRect(2, TempRect);
7146  Display->Update(); // need to keep this since Update() not called for PlotSmallOutput as too slow
7147  }
7148 
7150 /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
7151  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
7152  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
7153  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
7154  [New] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
7155  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
7156  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
7157  occupies. Clearand... is called finally to clear earlier selection displays.
7158 */
7159  {
7160  TrainController->LogEvent("MouseMove + Copy or CutMoving & SelectPickedUp");
7161  if(X < 0)
7162  X = 0; // ensure pointer stays within display area
7163  if(X > (MainScreen->Width - 1))
7164  X = MainScreen->Width - 1;
7165  if(Y < 0)
7166  Y = 0;
7167  if(Y > (MainScreen->Height - 1))
7168  Y = MainScreen->Height - 1;
7171  ClearandRebuildRailway(15); // plots SelectBitmap at the position given by NewSelectBitmapHLoc & ...VLoc
7172  }
7173 
7175  {
7176  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & TextFoundFlag");
7178  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7180  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7181 
7182  TextHandler->TextPtrAt(26, TextItem)->HPos = NewHPos;
7183  TextHandler->TextPtrAt(27, TextItem)->VPos = NewVPos;
7185  }
7186 
7188  {
7189  TrainController->LogEvent("MouseMove + MoveTextOrGraphic & UserGraphicFoundFlag");
7191  NewHPos = TextOrUserGraphicGridVal * (div(NewHPos, TextOrUserGraphicGridVal).quot);
7193  NewVPos = TextOrUserGraphicGridVal * (div(NewVPos, TextOrUserGraphicGridVal).quot);
7194 
7198  }
7199  }
7200  Utilities->CallLogPop(70);
7201  }
7202  catch(const Exception &e)
7203  {
7204  ErrorLog(22, e.Message);
7205  }
7206 }
7207 
7208 // ---------------------------------------------------------------------------
7209 void __fastcall TInterface::MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
7210 {
7211 /* [Repeated from MouseDown] - When 'select' chosen from the Edit menu (only available in 'AddTrack') conditions are set ready to enclose a rectangular screen area
7212  using MouseMove. When MouseDown occurs the starting point is marked (wrt whole railway, not just the screen) and stored in
7213  SelectStartPair. If the mouse button is released and a new start position selected then the earlier one is discarded. Providing the
7214  button is held down subsequent actions occur during MouseMove (to display the changing rectangle) and MouseUp to define the final
7215  selected rectangle.
7216  [Repeated from MouseMove] - At this point the select starting position has been defined in SelectStartPair, and the current mouse position is defined (wrt whole
7217  railway) in HLoc & VLoc from the screen positions X & Y by GetTrackLocsFromScreenPos. Both are incremented so that the rectangle
7218  includes the current point (if no mouse movement at all occurs then a 1 x 1 rectangle is displayed). Limits are set to prevent the
7219  displayed rectangle extending off screen. Edges are set at 60 & 36 rather than 59 & 35 because the defined rectangle excludes the
7220  rightmost and bottom HLoc & VLoc values, if 59 & 35 were used the right & bottom screen edges wouldn't be reached. A TRect is then
7221  defined from SelectStartPair and the HLoc/VLoc values, Clearand... called to clear earlier rectangles, and a dashed edge drawn round
7222  the selection.
7223  [New] This function can take some time so an houglass cursor is displayed. The rectangle is fully defined, so the final screen X & Y
7224  values are translated into HLoc & VLoc values (wrt whole railway) and SelectEndPair set using them. The rectangle can be defined in any
7225  direction, so the end points may be before or after the starting points for both horizontal and vertical directions. Therefore the
7226  rectangle that will be used subsequently - SelectRect - is defined from SelectStart and SelectEnd allowing for any direction. Screen
7227  limits are set as during MouseMove, and a dashed edge drawn as before. Then a check is made to see if the final rectangle has any area,
7228  and if not 'Select' mode is kept and the function ends so that a new rectangle can be drawn, otherwise new menu items Cut, Copy & Delete,
7229  are enabled. Now the SelectBitmap is made ready by filling with white prior to the track bitmaps being copied. If this isn't done the
7230  track bitmaps are loaded from the top left hand corner and the rest becomes black - not what is wanted! The SelectVector (defined in
7231  TrackUnit) is then loaded with the elements enclosed by the rectangle, top to bottom and left to right, active track elements first then
7232  inactive track elements. Empty squares are ignored as are default (erased) elements. Now the SelectVector is read and the corresponding
7233  element bitmaps transferred to SelectBitmap in the appropriate positions, then a dashed border added. Finally the cursor is changed back
7234  to an arrow.
7235 */
7236  try
7237  {
7238  TrainController->LogEvent("MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7239  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MainScreenMouseUp," + AnsiString(Button) + "," + AnsiString(X) + "," + AnsiString(Y));
7240  WholeRailwayMoving = false; // added at v2.1.0
7241  Screen->Cursor = TCursor(-2); // Arrow; (to reset from four arrows when moving) added at v2.1.0
7243  {
7244  TrainController->LogEvent("MouseUp + TrackSelecting + mbLeftDown");
7245  Screen->Cursor = TCursor(-11); // Hourglass;
7246  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7247  Track->GetTrackLocsFromScreenPos(3, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
7248 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7249 // rightmost point and the VLoc value of the bottommost point
7250  if(EndHLoc >= StartHLoc)
7251  EndHLoc++;
7252  else
7253  StartHLoc++;
7254  if(EndVLoc >= StartVLoc)
7255  EndVLoc++;
7256  else
7257  StartVLoc++;
7258  if(StartHLoc >= EndHLoc)
7259  {
7260  SelectRect.left = EndHLoc;
7261  SelectRect.right = StartHLoc;
7262  }
7263  else
7264  {
7265  SelectRect.left = StartHLoc;
7266  SelectRect.right = EndHLoc;
7267  }
7268  if(StartVLoc >= EndVLoc)
7269  {
7270  SelectRect.top = EndVLoc;
7271  SelectRect.bottom = StartVLoc;
7272  }
7273  else
7274  {
7275  SelectRect.top = StartVLoc;
7276  SelectRect.bottom = EndVLoc;
7277  }
7282  if(SelectRect.left - Display->DisplayOffsetH < 0)
7284  if(SelectRect.top - Display->DisplayOffsetV < 0)
7289  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
7290  {
7291  SelectionValid = false;
7293  mbLeftDown = false;
7294  Screen->Cursor = TCursor(-2); // Arrow;
7295  Utilities->CallLogPop(71);
7296  return; // no rectangle
7297  }
7298  else
7299  {
7300  ReselectMenuItem->Enabled = false;
7301  CutMenuItem->Enabled = true;
7302  CopyMenuItem->Enabled = true;
7303  FlipMenuItem->Enabled = true;
7304  MirrorMenuItem->Enabled = true;
7305  RotRightMenuItem->Enabled = true;
7306  RotLeftMenuItem->Enabled = true;
7307  RotateMenuItem->Enabled = true;
7308  PasteMenuItem->Enabled = false;
7309 // PasteWithAttributesMenuItem->Enabled = false; //new menu item for v2.2.0 only enabled after cutting
7310  DeleteMenuItem->Enabled = true;
7311  if(Track->IsTrackFinished())
7312  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
7313  else
7314  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
7315  SelectBiDirPrefDirsMenuItem->Visible = false;
7316  CancelSelectionMenuItem->Enabled = true;
7317  // set SelectBitmap
7318  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
7319  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
7320 
7321  // fill it with transparent white (i.e. use Draw) else graphics all plot from top left hand corner
7322  for(int H = 0; H < (SelectBitmap->Width) / 16; H++)
7323  {
7324  for(int V = 0; V < (SelectBitmap->Height) / 16; V++)
7325  {
7326  SelectBitmap->Canvas->Draw(H * 16, V * 16, RailGraphics->bmSolidBgnd);
7327  // NB in above if use bmTransparent it ISN'T transparent, but if use the non-transparent bmSolidBgnd it IS transparent
7328  // presumably superimposing a transparent bitmap onto a transparent bitmap makes the result non-transparent!
7329  }
7330  }
7331 
7332  // store elements in Track->SelectVector, active elements first then inactive so active element plotted first during paste
7333  // clear the vector first
7335  TTrackElement TempElement; // default element
7336  bool FoundFlag;
7337  for(int x = SelectRect.left; x < SelectRect.right; x++)
7338  {
7339  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7340  {
7341  int ATVecPos = Track->GetVectorPositionFromTrackMap(2, x, y, FoundFlag);
7342  if(FoundFlag)
7343  {
7344  TempElement = Track->TrackElementAt(440, ATVecPos);
7345  if(TempElement.SpeedTag > 0)
7346  Track->SelectPush(TempElement); // don't store erase elements
7347  }
7348  }
7349  }
7350  // now store inactive elements
7351  for(int x = SelectRect.left; x < SelectRect.right; x++)
7352  {
7353  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7354  {
7355  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(2, x, y, FoundFlag);
7356  if(FoundFlag)
7357  {
7358  TempElement = Track->InactiveTrackElementAt(30, IATVecPair.first);
7359  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
7360  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
7361  {
7362  TempElement = Track->InactiveTrackElementAt(31, IATVecPair.second);
7363  Track->SelectPush(TempElement);
7364  }
7365  }
7366  }
7367  }
7368  // store text items
7369  int LowSelectHPos = SelectRect.left * 16;
7370  int HighSelectHPos = SelectRect.right * 16;
7371  int LowSelectVPos = SelectRect.top * 16;
7372  int HighSelectVPos = SelectRect.bottom * 16;
7373  TextHandler->SelectTextVector.clear();
7374  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
7375  {
7376  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
7377  {
7378  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
7379  HighSelectVPos))
7380  {
7381  // have to create a new TextItem in order to create a new Font object
7382  // BUT: only create new items where they don't appear as named location names
7383  // in SelectVector, since those names shouldn't be copied or pasted.
7384  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
7385  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
7386  bool SelectVectorNamedElement = false;
7387  AnsiString SelectTextString; // new at v2.2.0
7388  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
7389  {
7390  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
7391  {
7392  SelectVectorNamedElement = true;
7393  break;
7394  }
7395  }
7396  if(SelectVectorNamedElement) // changed at v2.2.0
7397  {
7398  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
7399  }
7400  else // new at v2.2.0
7401  {
7402  SelectTextString = TextPtr->TextString;
7403  }
7404  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
7405  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
7406  }
7407  }
7408  }
7409  // store graphic items, but first clear SelectGraphicVector
7410  Track->SelectGraphicVector.clear();
7411  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
7412  {
7413  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
7414  UserGraphicPtr++)
7415  {
7416  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) &&
7417  (UserGraphicPtr->VPos >= LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
7418  {
7419  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
7420  }
7421  }
7422  }
7423 // new method - direct copying of existing selection so text included
7424  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
7425  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
7426  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
7427  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
7428  SelectionValid = true;
7429  }
7430  Screen->Cursor = TCursor(-2); // Arrow;
7431  }
7432 
7434  {
7435  TrainController->LogEvent("MouseUp + PrefDirSelecting + mbLeftDown");
7436  Screen->Cursor = TCursor(-11); // Hourglass;
7437 
7438  int EndHLoc, EndVLoc, StartHLoc = SelectStartPair.first, StartVLoc = SelectStartPair.second;
7439  Track->GetTrackLocsFromScreenPos(6, EndHLoc, EndVLoc, X, Y); // these values don't allow for offsets so add in later
7440 // to make the rectangle inclusive of the start and current points, need to increase the HLoc value of the
7441 // rightmost point and the VLoc value of the bottommost point
7442  if(EndHLoc >= StartHLoc)
7443  EndHLoc++;
7444  else
7445  StartHLoc++;
7446  if(EndVLoc >= StartVLoc)
7447  EndVLoc++;
7448  else
7449  StartVLoc++;
7450  if(StartHLoc >= EndHLoc)
7451  {
7452  SelectRect.left = EndHLoc;
7453  SelectRect.right = StartHLoc;
7454  }
7455  else
7456  {
7457  SelectRect.left = StartHLoc;
7458  SelectRect.right = EndHLoc;
7459  }
7460  if(StartVLoc >= EndVLoc)
7461  {
7462  SelectRect.top = EndVLoc;
7463  SelectRect.bottom = StartVLoc;
7464  }
7465  else
7466  {
7467  SelectRect.top = StartVLoc;
7468  SelectRect.bottom = EndVLoc;
7469  }
7474  if(SelectRect.left - Display->DisplayOffsetH < 0)
7476  if(SelectRect.top - Display->DisplayOffsetV < 0)
7481  if((SelectRect.top == SelectRect.bottom) || (SelectRect.left == SelectRect.right))
7482  {
7484  mbLeftDown = false;
7485  Screen->Cursor = TCursor(-2); // Arrow;
7486  Utilities->CallLogPop(1551);
7487  return; // no rectangle
7488  }
7489  else
7490  {
7491  SelectBiDirPrefDirsMenuItem->Enabled = true;
7492  CancelSelectionMenuItem->Enabled = true;
7493  // don't need SelectBitmap for PrefDir selection
7494 
7495  // store active elements in Track->SelectVector, ignore inactive elements
7496  // clear the vector first
7498  TTrackElement TempElement; // default element
7499  bool FoundFlag;
7500  for(int x = SelectRect.left; x < SelectRect.right; x++)
7501  {
7502  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
7503  {
7504  int ATVecPos = Track->GetVectorPositionFromTrackMap(43, x, y, FoundFlag);
7505  if(FoundFlag)
7506  {
7507  TempElement = Track->TrackElementAt(729, ATVecPos);
7508  if(TempElement.SpeedTag > 0)
7509  Track->SelectPush(TempElement); // don't store erase elements
7510  }
7511  }
7512  }
7513  }
7514  Screen->Cursor = TCursor(-2); // Arrow;
7515  }
7516 
7518 /* [Repeated from MouseDown] - The same actions apply on MouseDown whether Copy or Cut selected from the menu. First the horizontal and vertical mouse position is
7519  checked and unless it lies within the selected rectangle and not within 4 pixels of an edge the pickup fails and the function returns.
7520  Otherwise flag SelectPickedUp is set to true (to allow it to move during MouseMove and remain in place at MouseUp) and the mouse position
7521  is saved in SelectBitmapMouseLocX & Y for use later in MouseMove & MouseUp.
7522  [Repeated from MouseMove] - The same actions apply on MouseMove whether Copy or Cut selected from the menu. The X & Y mouse positions are checked and set to
7523  stay within the display area. Then the current selection H & V positions are stored in NewSelectBitmapHLoc & VLoc.
7524  These change continually while the mouse and the selection are moving, they are only read on MouseUp to retain the position that it then
7525  occupies. Clearand... is called finally to clear earlier selection displays.
7526  [New] - The only action here is to transfer the values of NewSelectBitmapHLoc & VLoc to SelectBitmapHLoc & VLoc so that the selection
7527  stays in the same position (Clearand... checks whether the mouse is moving (both mbLeftDown & SelectPickedUp true) or stopped (either
7528  mbLeftDown or SelectPickedUp false) and uses NewSelectBitmapHLoc & VLoc or SelectBitmapHLoc & SelectBitmapVLoc respectively.
7529 */
7530  {
7531  TrainController->LogEvent("MouseUp + Copy or CutMoving + mbLeftDown + SelectPickedUp");
7534  }
7535 
7536  mbLeftDown = false;
7537  Track->CalcHLocMinEtc(11);
7538  Utilities->CallLogPop(72);
7539  }
7540  catch(const Exception &e)
7541  {
7542  ErrorLog(23, e.Message);
7543  }
7544 }
7545 
7546 // ---------------------------------------------------------------------------
7547 
7548 void __fastcall TInterface::MasterClockTimer(TObject *Sender)
7549 {
7550  try
7551  {
7552  // don't call LogEvent here as would occur too often
7553  // have to allow in zoomout mode
7554  if(ErrorLogCalledFlag)
7555  return; // don't continue after an error
7556 
7557  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MasterClockTimer");
7558  // put counter outside Clock2 as that may be missed
7559  LCResetCounter++;
7560 // this checks LCs every 20 clock ticks (1 sec) & raises barriers if no route & no train present, to avoid delays due to too frequent calls
7561  if(LCResetCounter > 19)
7562  LCResetCounter = 0;
7564  if(WarningFlashCount > 4)
7565  WarningFlashCount = 0;
7566  if(WarningFlashCount == 0)
7567  {
7569  }
7570 
7571  if(Utilities->CallLog.size() > 50) // use CTRL ALT 2 to see CallLogSize as program operates
7572  {
7573  throw Exception("Warning - Utilities->CallLog contains more than 50 items"); // check before clock stopped
7574  }
7575 
7577  // stopped during 'Paused', when modal windows appear - Popup menu & ShowMessage, and at other times
7578  {
7579  // RestartTime is TTClockTime when operation pauses (timetable start time initially),
7580  // BaseTime is CurrentDateTime() when operation restarts
7581 
7582 // clock speed multiplier
7583  double RealTimeDouble = double(TDateTime::CurrentDateTime() - TrainController->BaseTime);
7584  TrainController->TTClockTime = TDateTime(TTClockSpeed * RealTimeDouble) + TrainController->RestartTime;
7585 // TrainController->TTClockTime = TDateTime::CurrentDateTime() - TrainController->BaseTime + TrainController->RestartTime;
7586  }
7587 
7588  TotalTicks++;
7590  {
7591  MissedTicks++;
7592  Utilities->CallLogPop(774);
7593  return;
7594  }
7595  Utilities->Clock2Stopped = true; //don't allow overlapping calls
7596  ClockTimer2(0);
7597  Utilities->Clock2Stopped = false;
7598  Utilities->CallLogPop(73);
7599  }
7600  catch(const Exception &e)
7601  {
7602  ErrorLog(24, e.Message);
7603  }
7604 }
7605 
7606 // ---------------------------------------------------------------------------
7607 
7608 void TInterface::ClockTimer2(int Caller)
7609 {
7610 // called every 50mSec
7611  try
7612  {
7613  // have to allow in zoomout mode
7614  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ClockTimer2");
7615 
7616  // dropped at 2.0.0 because RestoreFocusPanel->SetFocus(); hides the help screen
7617  // If a button holds focus then all that is needed is to click the screen and the arrow keys work correctly
7618 
7619 /* Dropped when new .chm help file introduced at v2.0.0 - this hid it after ~20ms. Replaced by a new section in
7620  MainScreenMouseDown where focus restored to screen when click anywhere on screen, allowing navigation keys to
7621  move screen when clicked if focus had been captured by another panel when these keys just cycle through the panel buttons
7622 
7623  bool FocusRestoreAllowedFlag = true; //added at v1.3.0
7624 
7625  if(TextBox->Focused() || DistanceBox->Focused() || SpeedLimitBox->Focused() || LocationNameTextBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() ||
7626  SpeedEditBox2->Focused() || LocationNameComboBox->Focused() || AddSubMinsBox->Focused() || SpeedEditBox->Focused() || PowerEditBox->Focused() || OneEntryTimetableMemo->Focused() ||
7627  AddPrefDirButton->Focused()) //Added at v1.3.0. If any of these has focus then they keep it until they release it. AddPrefDirButton is included as it should keep focus
7628  FocusRestoreAllowedFlag = false; //when it has it - eases the setting of PrefDirs, also this button becomes disabled after use so focus returns to Interface naturally
7629 
7630  if(!Focused() && FocusRestoreAllowedFlag && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0)) //condition added at v1.3.0 to ensure focus returned to
7631  //Interface (so arrow keys work to move screen) & not left at any of the buttons or other Windows controls
7632  //include the Windows API functions to test that the mouse buttons are not down (strictly only need left but user may have mapped the left onto the right so test both) - if not
7633  //tested then don't always respond to button clicks on navigation and other buttons because the focus can be grabbed back from the button by RestoreFocusPanel before the button
7634  //can respond (takes about 200mSec from click to response) a delay is also included to doubly avoid the button losing focus as above
7635  {
7636  ClockTimer2Count++; //doesn't matter what value it starts at on first use, it will soon revert to 0
7637  if(ClockTimer2Count > 10) ClockTimer2Count = 0; //half second delay
7638  if(ClockTimer2Count == 0)
7639  {
7640  RestoreFocusPanel->Visible = true;
7641  RestoreFocusPanel->Enabled = true;
7642  RestoreFocusPanel->BringToFront();
7643  //RestoreFocusPanel->SetFocus(); //to remove focus from anything else
7644  RestoreFocusPanel->Enabled = false; //to remove focus from RestoreFocusPanel & return it to Interface
7645  RestoreFocusPanel->Visible = false;
7646  }
7647  }
7648  else ClockTimer2Count = 0; //reset to 0 so ensure full delay occurs before RestoreFocusPanel grabs focus from anything else
7649 */
7650 
7651  CallLogTickerLabel->Caption = Utilities->CallLog.size(); // diagnostic test function to ensure all CallLogs are popped - visibility
7652  // toggled by 'Ctrl Alt 2' when Interface form has focus
7653 
7654  // set current time
7655  TDateTime Now = TrainController->TTClockTime;
7656 
7661 
7662  if(OperatorActionPanel->Visible)
7666  TrainController->OpActionPanelHintDelayCounter = 60; // new at v2.2.0
7667 
7668  TrainController->RandomFailureCounter++; // new at v2.4.0 counts up for 53 seconds then resets
7670  {
7672  }
7673 
7674 // Update Displayed Clock - resets to 0 at 96hours
7676 
7677 // Below added at v2.1.0 to ensure WholeRailwayMoving flag reset when not moving (when rh mouse button up) as sometimes misses
7678 // MouseUp events, probably due to a clash between a moving event and a mouse up event. Note that checks that both mouse buttons are up because
7679 // function only checks the physical buttons, not the logical buttons. Most sig bit of return value set form key down.
7680  if(WholeRailwayMoving && (GetAsyncKeyState(VK_LBUTTON) >= 0) && (GetAsyncKeyState(VK_RBUTTON) >= 0))
7681  {
7682  WholeRailwayMoving = false;
7683  Screen->Cursor = TCursor(-2); // Arrow
7684  }
7685 
7686 // save session if required
7687  if(SaveSessionFlag)
7688  {
7689  SaveSession(0);
7690  SaveSessionFlag = false;
7691  }
7692 // load session if required
7693  if(LoadSessionFlag)
7694  {
7695  if(ClearEverything(3))
7696  {
7697  LoadSession(0);
7698  }
7699  LoadSessionFlag = false;
7700  }
7701 
7702 // check if any LCs need barriers raising
7703 
7705  {
7707  {
7708  for(int x = Track->BarriersDownVector.size() - 1; x >= 0; x--)
7709  {
7710  bool TrainPresent = false;
7712  TrainPresent))
7713  {
7714  if(TrainPresent)
7715  {
7716  Track->BarriersDownVector.at(x).TrainPassed = true;
7717  }
7718  }
7719  else
7720  {
7721  Track->LCChangeFlag = true;
7723  // check if have exceeded the allowance (3 minutes for a train having passed or 0 for not) and add it to the overall excess time
7724  TDateTime TempExcessLCDownTime;
7725  if(Track->BarriersDownVector.at(x).TrainPassed)
7726  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime - TDateTime(180.0 / 86400);
7727  else
7728  TempExcessLCDownTime = TrainController->TTClockTime - CLC.StartTime;
7729  if(TempExcessLCDownTime > TDateTime(0))
7730  TrainController->ExcessLCDownMins += (double(TempExcessLCDownTime) * 1440);
7731 
7732  CLC.StartTime = TrainController->TTClockTime; // reset these 3 members
7735  Track->SetLinkedLevelCrossingBarrierAttributes(0, CLC.HLoc, CLC.VLoc, 2); // set attr to 2 for changing state
7736  Track->ChangingLCVector.push_back(CLC);
7737  Track->BarriersDownVector.erase(Track->BarriersDownVector.begin() + x);
7738  }
7739  }
7740  }
7741  }
7742 // clear LCChangeFlag if no LCs changing
7743  if(Track->ChangingLCVector.empty())
7744  {
7745  Track->LCChangeFlag = false;
7746  }
7747 
7748 // remove any single route elements if operating, but only if not constructing a route, else if extending the single route
7749 // element it may be removed prior to conversion & cause an error
7750 
7751 // note that if a train enters at a continuation and a signal is next but one to the continuation then the route element at that
7752 // signal won't be removed because the train's LagElement is still -1 and trains only remove route elements when LagElement is > -1.
7753 // This also means that a preferred route can't be cancelled as it's under a train, but it's probably not worth adding a patch just for
7754 // this, it shouldn't interfere with operation.
7756  {
7757  bool ElementRemovedFlag = false; // introduced at v0.6 to avoid calling Clearand.... multiple times
7758  for(unsigned int x = 0; x < AllRoutes->AllRoutesSize(); x++)
7759  {
7760  if(AllRoutes->GetFixedRouteAt(187, x).PrefDirSize() == 1)
7761  {
7762  // only allow route element to be removed if not selected for a route start otherwise StartSelectionRouteID will be
7763  // set & will fail at convert
7765  {
7767  AllRoutes->RemoveRouteElement(20, PDE.HLoc, PDE.VLoc, PDE.GetELink());
7768  ElementRemovedFlag = true;
7769  TrainController->LogEvent("SingleRouteElementRemoved, H = " + AnsiString(PDE.HLoc) + ", V = " + AnsiString(PDE.VLoc));
7770  }
7771  }
7772  }
7773  if(!Display->ZoomOutFlag && ElementRemovedFlag)
7774  ClearandRebuildRailway(66); // if zoomed out ignore, will display correctly when zoom in
7775  // if leave the Zoomout condition out then the zoom out will spontaneously cancel and the track won't display because
7776  // PlotOutput returns if zoomed out, and the zoom out flag isn't reset until the end of Clearand.....
7777  // this was moved outside the for.. next.. loop in v0.6 as it could be called multiple times and slowed down operation (noticeable with a fast clock)
7778  }
7779 // stop clock if hover over a warning
7780  bool WH1 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog1->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog1->Width + OutputLog1->Left))
7781  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog1->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog1->Height + OutputLog1->Top))
7782  && OutputLog1->Caption != "";
7783  bool WH2 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog2->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog2->Width + OutputLog2->Left))
7784  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog2->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog2->Height + OutputLog2->Top))
7785  && OutputLog2->Caption != "";
7786  bool WH3 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog3->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog3->Width + OutputLog3->Left))
7787  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog3->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog3->Height + OutputLog3->Top))
7788  && OutputLog3->Caption != "";
7789  bool WH4 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog4->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog4->Width + OutputLog4->Left))
7790  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog4->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog4->Height + OutputLog4->Top))
7791  && OutputLog4->Caption != "";
7792  bool WH5 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog5->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog5->Width + OutputLog5->Left))
7793  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog5->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog5->Height + OutputLog5->Top))
7794  && OutputLog5->Caption != "";
7795  bool WH6 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog6->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog6->Width + OutputLog6->Left))
7796  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog6->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog6->Height + OutputLog6->Top))
7797  && OutputLog6->Caption != "";
7798  bool WH7 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog7->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog7->Width + OutputLog7->Left))
7799  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog7->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog7->Height + OutputLog7->Top))
7800  && OutputLog7->Caption != "";
7801  bool WH8 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog8->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog8->Width + OutputLog8->Left))
7802  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog8->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog8->Height + OutputLog8->Top))
7803  && OutputLog8->Caption != "";
7804  bool WH9 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog9->Left) && (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog9->Width + OutputLog9->Left))
7805  && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog9->Top) && (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog9->Height + OutputLog9->Top))
7806  && OutputLog9->Caption != "";
7807  bool WH10 = (Mouse->CursorPos.x >= ClientOrigin.x + OutputLog10->Left) &&
7808  (Mouse->CursorPos.x < (ClientOrigin.x + OutputLog10->Width + OutputLog10->Left)) && (Mouse->CursorPos.y >= ClientOrigin.y + OutputLog10->Top) &&
7809  (Mouse->CursorPos.y < (ClientOrigin.y + OutputLog10->Height + OutputLog10->Top)) && OutputLog10->Caption != "";
7810 
7811  if(WH1 || WH2 || WH3 || WH4 || WH5 || WH6 || WH7 || WH8 || WH9 || WH10)
7812  {
7813  if(!WarningHover)
7814  {
7815  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
7817  WarningHover = true;
7818  }
7819  }
7820  else if(WarningHover)
7821  {
7822  WarningHover = false;
7823  TrainController->BaseTime = TDateTime::CurrentDateTime();
7825  }
7826 
7827 // development panel - visibility toggled by 'Ctrl Alt 3' when Interface form has focus
7828  if(DevelopmentPanel->Visible)
7829  {
7830  int Position;
7831  TTrackElement TrackElement;
7832  AnsiString Type[15] =
7833  {"Simple", "Crossover", "Points", "Buffers", "Bridge", "SignalPost", "Continuation", "Platform", "GapJump", "FootCrossing", "Unused", "Concourse",
7834  "Parapet", "NamedNonStationLocation", "Erase"};
7835 
7836  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
7837  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
7838  int HLoc, VLoc;
7839  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
7840  DevelopmentPanel->Caption = CurDir + " " + MouseStr;
7841  Track->GetTrackLocsFromScreenPos(7, HLoc, VLoc, ScreenX, ScreenY);
7842  if(Track->FindNonPlatformMatch(1, HLoc, VLoc, Position, TrackElement))
7843  {
7844  DevelopmentPanel->Caption = MouseStr + "; TVPos: " + AnsiString(Position) + "; H: " + AnsiString(HLoc) + "; V: " + AnsiString(VLoc) +
7845  "; SpTg: " + AnsiString(TrackElement.SpeedTag) + "; Type: " + Type[TrackElement.TrackType] + "; Att: " + AnsiString(TrackElement.Attribute)
7846  + "; TrID: " + AnsiString(TrackElement.TrainIDOnElement) + "; TrID01: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos01) +
7847  "; TrID23: " + AnsiString(TrackElement.TrainIDOnBridgeTrackPos23) + "; " + TrackElement.LocationName + "; " +
7848  TrackElement.ActiveTrackElementName;
7849 // + "; OAHintCtr: " + TrainController->OpActionPanelHintDelayCounter;
7850  }
7851  }
7852 
7853  if(Level1Mode == TimetableMode)
7854  {
7855 /*These are for Shift Key shortcuts. Unless 'Click()' execution occurs after the key is pressed Windows stores the key until after any code is executed then selects
7856 the timetable entry that begins with the letter corresponding to the key. See DevHistory.txt for the version after v2.4.3 for details.
7857 
7858 First make sure the selected entry is the Highlighted entry, but only if both mouse buttons are up, to make sure AllEntriesTTListBoxMouseUp runs first or TopIndex
7859 likely to be set to the wrong position since when ...Selected... runs it sets TopIndex accordingly. Then when ...MouseUp runs it will use the wrong value and select
7860 the entry that the mouse is now on rather than the one that was chosen.
7861 Later addition: Set member variable AllEntriesTTListBox->TopIndex here if any flag set so when Copy or any other key function runs the top index is correct
7862 */
7863  if((GetKeyState(VK_LBUTTON) >= 0) && (GetKeyState(VK_RBUTTON) >= 0) && (TTCurrentEntryPtr > 0)) //high order bit set to 1 when button down, so arithmetically it is negative
7864  { //TTCurrentEntryPtr == 0 when create a timetable
7865  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
7866  }
7867  if(AnyTTKeyFlagSet()) //true if any of the below flags set
7868  {
7869  AllEntriesTTListBox->TopIndex = AllEntriesTTListBoxTopPosition; //reset it to the value before the key press changes it (see FormKeyDown)
7870  }
7872  {
7873  PreviousTTEntryButton->Click();
7874  SetTopIndex(0);
7875  PreviousTTEntryKeyFlag = false;
7876  }
7877  else if(NextTTEntryKeyFlag)
7878  {
7879  NextTTEntryButton->Click();
7880  SetTopIndex(1);
7881  NextTTEntryKeyFlag = false;
7882  }
7883  else if(MoveTTEntryUpKeyFlag)
7884  {
7885  MoveTTEntryUpButton->Click();
7886  SetTopIndex(2);
7887  MoveTTEntryUpKeyFlag = false;
7888  }
7889  else if(MoveTTEntryDownKeyFlag)
7890  {
7891  MoveTTEntryDownButton->Click();
7892  SetTopIndex(3);
7893  MoveTTEntryDownKeyFlag = false;
7894  }
7895  else if(CopyTTEntryKeyFlag)
7896  {
7897  CopyTTEntryButton->Click();
7898  SetTopIndex(4);
7899  CopyTTEntryKeyFlag = false;
7900  }
7901  else if(CutTTEntryKeyFlag)
7902  {
7903  CutTTEntryButton->Click();
7904  SetTopIndex(5);
7905  CutTTEntryKeyFlag = false;
7906  }
7907  else if(PasteTTEntryKeyFlag)
7908  {
7909  PasteTTEntryButton->Click();
7910  SetTopIndex(6);
7911  PasteTTEntryKeyFlag = false;
7912  }
7913  else if(DeleteTTEntryKeyFlag)
7914  {
7915  DeleteTTEntryButton->Click();
7916  SetTopIndex(7);
7917  DeleteTTEntryKeyFlag = false;
7918  }
7919  else if(NewTTEntryKeyFlag)
7920  {
7921  NewTTEntryButton->Click();
7922  SetTopIndex(8);
7923  NewTTEntryKeyFlag = false;
7924  }
7925  else if(AZOrderKeyFlag)
7926  {
7927  AZOrderButton->Click();
7928  SetTopIndex(9);
7929  AZOrderKeyFlag = false;
7930  }
7932  {
7933  TTServiceSyntaxCheckButton->Click();
7934  SetTopIndex(12);
7936  }
7937  else if(ValidateTimetableKeyFlag)
7938  {
7939  ValidateTimetableButton->Click();
7940  SetTopIndex(13);
7941  ValidateTimetableKeyFlag = false;
7942  }
7943  else if(SaveTTKeyFlag)
7944  {
7945  SaveTTButton->Click();
7946  SetTopIndex(14);
7947  SaveTTKeyFlag = false;
7948  }
7949  else if(SaveTTAsKeyFlag)
7950  {
7951  SaveTTAsButton->Click();
7952  SetTopIndex(15);
7953  SaveTTAsKeyFlag = false;
7954  }
7955  else if(RestoreTTKeyFlag)
7956  {
7957  RestoreTTButton->Click();
7958  SetTopIndex(16);
7959  RestoreTTKeyFlag = false;
7960  }
7961  else if(ExportTTKeyFlag)
7962  {
7963  ExportTTButton->Click();
7964  SetTopIndex(17);
7965  ExportTTKeyFlag = false;
7966  }
7967  else if(ConflictAnalysisKeyFlag)
7968  {
7969  ConflictAnalysisButton->Click();
7970  SetTopIndex(18);
7971  ConflictAnalysisKeyFlag = false;
7972  }
7973 
7974 
7975 // highlight timetable entry if in tt mode (have to call this regularly so will scroll with the listbox)
7976  if(!TimetableEditVector.empty() && (TTCurrentEntryPtr > 0))
7977  {
7979  }
7980  else
7981  {
7983  }
7984  }
7985 
7986 // set cursor
7988  {
7989  if(!TempCursorSet)
7990  {
7991  TempCursor = Screen->Cursor;
7992  TempCursorSet = true;
7993  }
7994  Screen->Cursor = TCursor(-11); // Hourglass
7995  }
7996  else
7997  {
7998  if(TempCursorSet)
7999  {
8000  Screen->Cursor = TempCursor;
8001  TempCursorSet = false;
8002  }
8003  }
8004 
8005  if(Level2OperMode == Operating)
8006  {
8007  TrainController->Operate(0); // ensure this called AFTER the single element route removal to ensure any single elements removed
8008  // prior to CallingOnAllowed being called (in UpdateTrain) as that sets a route from the stop signal
8010  {
8011  UpdateOperatorActionPanel(0); // new at v2.2.0 to update panel when train OpTimeToAct updated (updated earlier)
8012  }
8013  TrainController->SignallerTrainRemovedOnAutoSigsRoute = false; // added at v1.3.0 to ensure doesn't persist beyond one call
8014  }
8015 
8016  else if(Level2OperMode == Paused) //added after v2.4.3 to show actions due after a session file reloaded
8017  {
8019  {
8020  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
8021  {
8023  }
8026  }
8027  }
8028 
8029 // plot trains in ZoomOut mode & flash trains where attention needed alternately on & off at each call
8030 // by examining Flash
8031  if((Level1Mode == OperMode) && (Display->ZoomOutFlag))
8032  {
8034  }
8035 
8036 // Deal with any flashing graphics
8038  {
8039  FlashingGraphics(0, Now); // only call when WarningFlash changes
8040  if(Level1Mode == OperMode)
8041  {
8042  if(WarningFlash)
8043  {
8045  {
8046  CrashImage->Visible = true;
8047  }
8049  {
8050  DerailImage->Visible = true;
8051  }
8053  {
8054  SPADImage->Visible = true;
8055  }
8057  {
8058  TrainFailedImage->Visible = true;
8059  }
8061  {
8062  CallOnImage->Visible = true;
8063  }
8065  {
8066  SignalStopImage->Visible = true;
8067  }
8069  {
8070  BufferAttentionImage->Visible = true;
8071  }
8072  }
8073  else
8074  {
8075  CrashImage->Visible = false;
8076  DerailImage->Visible = false;
8077  SPADImage->Visible = false;
8078  TrainFailedImage->Visible = false;
8079  CallOnImage->Visible = false;
8080  SignalStopImage->Visible = false;
8081  BufferAttentionImage->Visible = false;
8082  }
8083  }
8084  else
8085  {
8086  CrashImage->Visible = false;
8087  DerailImage->Visible = false;
8088  SPADImage->Visible = false;
8089  TrainFailedImage->Visible = false;
8090  CallOnImage->Visible = false;
8091  SignalStopImage->Visible = false;
8092  BufferAttentionImage->Visible = false;
8093  }
8094  } // if(WarningFlashCount == 0)
8095  // set buttons etc as appropriate
8097  // if forced route cancellation flag set redisplay to clear the cancelled route
8099  {
8101  AllRoutes->RebuildRailwayFlag = false;
8102  }
8103  // deal with approach locking
8105  // deal with ContinuationAutoSigList
8107  // FloatingLabel function
8108  if((TrackInfoOnOffMenuItem->Caption == "Hide") || (TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") ||
8109  (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable"))
8110  {
8111  TrackTrainFloat(0);
8112  }
8113  else
8114  {
8115  FloatingPanel->Visible = false;
8116  }
8117  // PerformanceLog check function
8118 /*
8119  if(IsPerformancePanelObscuringFloatingLabel(0) && (ShowPerformancePanel))
8120  {
8121  PerformancePanel->Visible = false;
8122  }
8123  else
8124  {
8125 */
8127  {
8128  PerformancePanel->Visible = true;
8129  }
8130  else
8131  {
8132  PerformancePanel->Visible = false;
8133  }
8134 
8136  {
8137  OperatorActionPanel->Visible = true;
8138  }
8139  else
8140  {
8141  OperatorActionPanel->Visible = false;
8142  }
8143 
8144 // }
8145 
8146  // check if a moving train is present on a route-under-construction start element & cancel it if so
8147  if(RouteMode == RouteContinuing)
8148  {
8149  bool FoundFlag;
8150  int RouteStartVecPos;
8151  if(AutoSigsFlag)
8153  FoundFlag);
8154  else if(ConsecSignalsRoute)
8155  RouteStartVecPos = Track->GetVectorPositionFromTrackMap(8, (SigRouteStartMarker->GetHPos()) / 16, (SigRouteStartMarker->GetVPos()) / 16,
8156  FoundFlag);
8157  else
8159  FoundFlag);
8160  if(FoundFlag && (RouteStartVecPos > -1))
8161  {
8162  TTrackElement TrackElement = Track->TrackElementAt(485, RouteStartVecPos);
8163  if(TrackElement.TrainIDOnElement > -1)
8164  {
8165  if(!(TrainController->TrainVectorAtIdent(2, TrackElement.TrainIDOnElement).Stopped()))
8166  {
8168  // replot train as above erases the front element of the train
8170  }
8171  }
8172  }
8173  }
8174  Utilities->CallLogPop(81);
8175  }
8176  catch(const Exception &e)
8177  {
8178  ErrorLog(25, e.Message);
8179  }
8180 }
8181 
8182 // ---------------------------------------------------------------------------
8183 
8184 void __fastcall TInterface::CallingOnButtonClick(TObject *Sender)
8185 {
8186  try
8187  {
8188  TrainController->LogEvent("CallingOnButtonClick");
8189  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CallingOnButtonClick");
8190  if(CallingOnButton->Down)
8191  {
8192  // CallingOnButton->Down = true;
8193  InfoPanel->Visible = true;
8194  InfoPanel->Caption = "CALLING ON: Select signal for call on";
8195  }
8196  else
8197  {
8198  // CallingOnButton->Down = false;
8200  }
8201  AutoRouteStartMarker->PlotOriginal(29, Display); // if overlay not plotted will ignore
8202  SigRouteStartMarker->PlotOriginal(30, Display); // if overlay not plotted will ignore
8203  NonSigRouteStartMarker->PlotOriginal(31, Display); // if overlay not plotted will ignore
8204  CallingOnButton->Enabled = false;
8205 // added at v1.3.0 to ensure doesn't retain focus - will be re-enabled during ClockTimer2 (in SetSaveMenuAndButtons) if required
8206  Utilities->CallLogPop(82);
8207  }
8208  catch(const Exception &e)
8209  {
8210  ErrorLog(26, e.Message);
8211  }
8212 }
8213 
8214 // ---------------------------------------------------------------------------
8215 void __fastcall TInterface::ScreenLeftButtonClick(TObject *Sender)
8216 {
8217  try
8218  {
8219  // have to allow in zoomout mode
8220  TrainController->LogEvent("ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8221  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenLeftButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8222  Screen->Cursor = TCursor(-11); // Hourglass;
8223  ScreenLeftButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8224  if(!Display->ZoomOutFlag)
8225  {
8226  if(CtrlKey)
8227  {
8228  Display->DisplayOffsetH -= 2;
8229  }
8230  else if(ShiftKey)
8231  {
8233  }
8234  else
8235  {
8237  }
8240  {
8242  }
8243  }
8244  else
8245  {
8246  if(CtrlKey)
8247  {
8249  }
8250  else if(ShiftKey)
8251  {
8253  }
8254  else
8255  {
8257  }
8258  Display->ClearDisplay(0);
8261  Track->PlotSmallRedGap(0);
8262  }
8263  ScreenLeftButton->Enabled = true;
8264  Screen->Cursor = TCursor(-2); // Arrow
8265  Utilities->CallLogPop(83);
8266  }
8267  catch(const Exception &e)
8268  {
8269  ErrorLog(27, e.Message);
8270  }
8271 }
8272 // ---------------------------------------------------------------------------
8273 
8274 void __fastcall TInterface::ScreenRightButtonClick(TObject *Sender)
8275 {
8276  try
8277  {
8278  // have to allow in zoomout mode
8279  TrainController->LogEvent("ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8280  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenRightButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8281  Screen->Cursor = TCursor(-11); // Hourglass;
8282  ScreenRightButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8283  if(!Display->ZoomOutFlag)
8284  {
8285  if(CtrlKey)
8286  {
8287  Display->DisplayOffsetH += 2;
8288  }
8289  else if(ShiftKey)
8290  {
8292  }
8293  else
8294  {
8296  }
8299  {
8301  }
8302  }
8303  else
8304  {
8305  if(CtrlKey)
8306  {
8308  }
8309  else if(ShiftKey)
8310  {
8312  }
8313  else
8314  {
8316  }
8317  Display->ClearDisplay(1);
8320  Track->PlotSmallRedGap(1);
8321  }
8322  ScreenRightButton->Enabled = true;
8323  Screen->Cursor = TCursor(-2); // Arrow
8324  Utilities->CallLogPop(84);
8325  }
8326  catch(const Exception &e)
8327  {
8328  ErrorLog(28, e.Message);
8329  }
8330 }
8331 // ---------------------------------------------------------------------------
8332 
8333 void __fastcall TInterface::ScreenDownButtonClick(TObject *Sender)
8334 {
8335  try
8336  {
8337  // have to allow in zoomout mode
8338  TrainController->LogEvent("ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8339  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenDownButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8340  Screen->Cursor = TCursor(-11); // Hourglass;
8341  ScreenDownButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8342  // BUT - it does prevent it from retaining focus - so can use the cursor keys to scroll the display without being captured by the buttons
8343  if(!Display->ZoomOutFlag)
8344  {
8345  if(CtrlKey)
8346  {
8347  Display->DisplayOffsetV += 2;
8348  }
8349  else if(ShiftKey)
8350  {
8352  }
8353  else
8354  {
8356  }
8359  {
8361  }
8362  }
8363  else
8364  {
8365  if(CtrlKey)
8366  {
8368  }
8369  else if(ShiftKey)
8370  {
8372  }
8373  else
8374  {
8376  }
8377  Display->ClearDisplay(2);
8380  Track->PlotSmallRedGap(2);
8381  }
8382  ScreenDownButton->Enabled = true;
8383  Screen->Cursor = TCursor(-2); // Arrow
8384  Utilities->CallLogPop(85);
8385  }
8386  catch(const Exception &e)
8387  {
8388  ErrorLog(29, e.Message);
8389  }
8390 }
8391 // ---------------------------------------------------------------------------
8392 
8393 void __fastcall TInterface::ScreenUpButtonClick(TObject *Sender)
8394 {
8395  try
8396  {
8397  // have to allow in zoomout mode
8398  TrainController->LogEvent("ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8399  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ScreenUpButtonClick" + AnsiString((short)ShiftKey) + AnsiString((short)CtrlKey));
8400  Screen->Cursor = TCursor(-11); // Hourglass;
8401  ScreenUpButton->Enabled = false; // to make multiple key presses less likely (not entirely successful)
8402  if(!Display->ZoomOutFlag)
8403  {
8404  if(CtrlKey)
8405  {
8406  Display->DisplayOffsetV -= 2;
8407  }
8408  else if(ShiftKey)
8409  {
8411  }
8412  else
8413  {
8415  }
8418  {
8420  }
8421  }
8422  else
8423  {
8424  if(CtrlKey)
8425  {
8427  }
8428  else if(ShiftKey)
8429  {
8431  }
8432  else
8433  {
8435  }
8436  Display->ClearDisplay(3);
8439  Track->PlotSmallRedGap(3);
8440  }
8441  ScreenUpButton->Enabled = true;
8442  Screen->Cursor = TCursor(-2); // Arrow
8443  Utilities->CallLogPop(86);
8444  }
8445  catch(const Exception &e)
8446  {
8447  ErrorLog(30, e.Message);
8448  }
8449 }
8450 // ---------------------------------------------------------------------------
8451 
8452 void __fastcall TInterface::ZoomButtonClick(TObject *Sender)
8453 {
8454  try
8455  {
8456  // have to allow in zoomout mode
8457  TrainController->LogEvent("ZoomButtonClick");
8458  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ZoomButtonClick");
8459  Screen->Cursor = TCursor(-11); // Hourglass;
8460  ZoomButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
8461  if(Display->ZoomOutFlag) // i.e resume zoomed in view
8462  {
8463  TrainController->LogEvent("ZoomButtonClick + ZoomOutFlag");
8464 // TLevel2OperMode TempLevel2OperMode = Level2OperMode;
8465  if(Level1Mode == BaseMode)
8466  {
8467  InfoPanel->Visible = false; // reset infopanel in case not set later
8468  InfoPanel->Caption = "";
8469  SetLevel1Mode(18);
8470  }
8471  else if(Level1Mode == TrackMode)
8472  {
8473  InfoPanel->Visible = false; // reset infopanel in case not set later
8474  InfoPanel->Caption = "";
8475  // set edit menu items
8477  SetLevel2TrackMode(33); // revert to earlier track mode from zoom
8478  }
8479  else if(Level1Mode == PrefDirMode)
8480  {
8482  SetLevel1Mode(19); // to redisplay infopanel caption "...select start..."
8483  else
8484  SetLevel2PrefDirMode(4); // revert to PrefDirContinuing PrefDir mode
8485  }
8486 // else if(Level1Mode == TrackMode) SetLevel1Mode();//just revert to basic track mode from zoom
8487 // else if(Level1Mode == PrefDirMode) SetLevel1Mode();//just revert to basic PrefDir mode from zoom
8488  else if(Level1Mode == TimetableMode)
8489  {
8490  InfoPanel->Visible = false;
8491  }
8492  // Don't include OperMode or RestartSessionOperMode as they reset the performance file
8493  else if(Level2OperMode == Operating) // similar to SetLevel2OperMode but without resetting BaseTime
8494  {
8495  OperateButton->Enabled = true;
8496  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
8497  ExitOperationButton->Enabled = true;
8499  }
8500  else if(Level2OperMode == Paused) // similar to SetLevel2OperMode but without resetting RestartTime
8501  {
8502  OperateButton->Enabled = true;
8503  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
8504  ExitOperationButton->Enabled = true;
8505  TTClockAdjButton->Enabled = true;
8508  }
8509  else if(Level2OperMode == PreStart)
8510  {
8511  OperateButton->Enabled = true;
8512  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
8513  ExitOperationButton->Enabled = true;
8514  TTClockAdjButton->Enabled = true;
8516  }
8517  Display->ZoomOutFlag = false; // reset this after level modes called so gap flash stays set if set to begin with
8519  ClearandRebuildRailway(43); // need to call this after ZoomOutFlag reset to display track, even if Clearand... already called
8520  // earlier during level mode setting - because until ZoomOutFlag reset PlotOutput plots nothing
8521  }
8522  else // set zoomed out view
8523  {
8524  TrainController->LogEvent("ZoomButtonClick + != ZoomOutFlag");
8525  Display->ZoomOutFlag = true;
8527  FileMenu->Enabled = false;
8528  ModeMenu->Enabled = false;
8529  EditMenu->Enabled = false;
8530  TextBox->Visible = false;
8531  LocationNameTextBox->Visible = false;
8532  TTClockAdjButton->Enabled = false;
8533 // DisablePanelsStoreMainMenuStates();//ensure Display->ZoomOutFlag set true before calling
8534  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
8535  int OVOffH_NVCentre = Display->DisplayOffsetH - (1.5 * Utilities->ScreenElementWidth);
8536 // start zoomout centre at DisplayOffsetH + 30 - zoomout width/2 = -(1.5 * 60)
8537  int LeftExcess = OVOffH_NVCentre - Track->GetHLocMin();
8538  int RightExcess = Track->GetHLocMax() - OVOffH_NVCentre - ((4 * Utilities->ScreenElementWidth) - 1);
8539  if((LeftExcess > 0) && (RightExcess > 0))
8540  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre;
8541  else if((LeftExcess > 0) && (RightExcess <= 0))
8542  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre + ((RightExcess) / (Utilities->ScreenElementWidth / 2)) *
8543  (Utilities->ScreenElementWidth / 2); // normalise to nearest screen
8544  else if((LeftExcess <= 0) && (RightExcess > 0))
8545  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre - ((LeftExcess) / (Utilities->ScreenElementWidth / 2)) * (Utilities->ScreenElementWidth / 2);
8546  else
8547  Display->DisplayZoomOutOffsetH = OVOffH_NVCentre; // no excess at either side, so display in centre
8548 
8549  int OVOffV_NVCentre = Display->DisplayOffsetV - (1.5 * Utilities->ScreenElementHeight);
8550  int TopExcess = OVOffV_NVCentre - Track->GetVLocMin();
8551  int BotExcess = Track->GetVLocMax() - OVOffV_NVCentre - ((4 * Utilities->ScreenElementHeight) - 1);
8552  if((TopExcess > 0) && (BotExcess > 0))
8553  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre;
8554  else if((TopExcess > 0) && (BotExcess <= 0))
8555  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre + ((BotExcess) / (Utilities->ScreenElementHeight / 2)) *
8556  (Utilities->ScreenElementHeight / 2); // normalise to nearest half screen
8557  else if((TopExcess <= 0) && (BotExcess > 0))
8558  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre - ((TopExcess) / (Utilities->ScreenElementHeight / 2)) * (Utilities->ScreenElementHeight / 2);
8559  else
8560  Display->DisplayZoomOutOffsetV = OVOffV_NVCentre; // no excess at either side, so display in centre
8561 
8562  Display->ClearDisplay(4);
8566  Track->PlotSmallRedGap(4);
8567  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomIn");
8568  }
8569  Screen->Cursor = TCursor(-2); // Arrow
8570  ZoomButton->Enabled = true; // restore, see above
8571  Utilities->CallLogPop(87);
8572  }
8573  catch(const Exception &e)
8574  {
8575  ErrorLog(31, e.Message);
8576  }
8577 }
8578 // ---------------------------------------------------------------------------
8579 
8580 void __fastcall TInterface::HomeButtonClick(TObject *Sender)
8581 {
8582  try
8583  {
8584  // have to allow in zoomout mode
8585  TrainController->LogEvent("HomeButtonClick");
8586  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",HomeButtonClick");
8587  Screen->Cursor = TCursor(-11); // Hourglass;
8588  HomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
8589  if(!Display->ZoomOutFlag) // zoomed in mode
8590  {
8591  TrainController->LogEvent("HomeButtonClick + zoomed in mode");
8595  {
8597  }
8598  }
8599  else
8600  {
8601  // zoomed out mode
8602  // start assuming normal view is at centre of ZoomOut & calc excesses at each side
8603  TrainController->LogEvent("HomeButtonClick + zoomed out mode");
8605  Display->ClearDisplay(9);
8608  Track->PlotSmallRedGap(5);
8609  }
8610  Screen->Cursor = TCursor(-2); // Arrow
8611  HomeButton->Enabled = true; // restore, see above
8612  Utilities->CallLogPop(88);
8613  }
8614  catch(const Exception &e)
8615  {
8616  ErrorLog(32, e.Message);
8617  }
8618 }
8619 
8620 // ---------------------------------------------------------------------------
8621 void __fastcall TInterface::NewHomeButtonClick(TObject *Sender)
8622 {
8623  try
8624  {
8625  TrainController->LogEvent("NewHomeButtonClick");
8626  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",NewHomeButtonClick");
8627  NewHomeButton->Enabled = false; // this takes focus away so the arrow keys can move the display (v2.0.0)
8628  if(!Display->ZoomOutFlag) // zoomed in mode
8629  {
8632  ResetChangedFileDataAndCaption(23, false); // false because no major changes made
8633  }
8634  else
8635  {
8638  }
8639  Utilities->CallLogPop(1188);
8640  NewHomeButton->Enabled = true; // restore, see above
8641  }
8642  catch(const Exception &e)
8643  {
8644  ErrorLog(174, e.Message);
8645  }
8646 }
8647 
8648 // ---------------------------------------------------------------------------
8649 void __fastcall TInterface::EditMenuClick(TObject *Sender)
8650  // added at v2.1.0 to allow CTRL+X, CTRL+C & CTRL+V in edit menu (see case BaseMode for more information)
8651 {
8652  try
8653  {
8654  CopyMenuItem->ShortCut = TextToShortCut("Ctrl+C");
8655  CutMenuItem->ShortCut = TextToShortCut("Ctrl+X");
8656  PasteMenuItem->ShortCut = TextToShortCut("Ctrl+V");
8657  }
8658  catch(const Exception &e)
8659  {
8660  ErrorLog(196, e.Message);
8661  }
8662 }
8663 
8664 // ---------------------------------------------------------------------------
8665 void __fastcall TInterface::SelectMenuItemClick(TObject *Sender)
8666 {
8667 // draw a rectangle with the left mouse button, enclosing whole 16 x 16 squares
8668  try
8669  {
8670  TrainController->LogEvent("SelectMenuItemClick");
8671  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectMenuItemClick");
8672  if(Level1Mode == TrackMode)
8673  {
8674  SelectionValid = false;
8676  SetLevel2TrackMode(34);
8677  }
8678  else if(Level1Mode == PrefDirMode)
8679  {
8682  }
8683  Utilities->CallLogPop(1189);
8684  }
8685  catch(const Exception &e)
8686  {
8687  ErrorLog(145, e.Message);
8688  }
8689 }
8690 
8691 // ---------------------------------------------------------------------------
8692 void __fastcall TInterface::ReselectMenuItemClick(TObject *Sender)
8693 {
8694  try
8695  {
8696  TrainController->LogEvent("ReselectMenuItemClick");
8697  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectMenuItemClick");
8698  if((SelectBitmap->Height == 0) || (SelectBitmap->Width == 0))
8699  {
8700  Utilities->CallLogPop(1424);
8701  return;
8702  }
8703 
8704  int TLHCH = SelectBitmapHLoc;
8705  int TLHCV = SelectBitmapVLoc;
8706  int BRHCH = TLHCH + (SelectBitmap->Width / 16);
8707  int BRHCV = TLHCV + (SelectBitmap->Height / 16);
8708  TRect NewSelectRect(TLHCH, TLHCV, BRHCH, BRHCV);
8709  SelectRect = NewSelectRect;
8711  // set bitmap to reselected area (may be different if flip or mirror had been selected earlier)
8712  TRect Dest(0, 0, SelectBitmap->Width, SelectBitmap->Height);
8713  TRect Source(((SelectRect.left - Display->DisplayOffsetH) * 16), ((SelectRect.top - Display->DisplayOffsetV) * 16),
8714  ((SelectRect.right - Display->DisplayOffsetH) * 16), ((SelectRect.bottom - Display->DisplayOffsetV) * 16));
8715  SelectBitmap->Canvas->CopyRect(Dest, MainScreen->Canvas, Source);
8716 
8717  SelectionValid = true;
8718  ReselectMenuItem->Enabled = false;
8719  CutMenuItem->Enabled = true;
8720  CopyMenuItem->Enabled = true;
8721  FlipMenuItem->Enabled = true;
8722  MirrorMenuItem->Enabled = true;
8723  RotRightMenuItem->Enabled = true;
8724  RotLeftMenuItem->Enabled = true;
8725  RotateMenuItem->Enabled = true;
8726  PasteMenuItem->Enabled = false;
8727  DeleteMenuItem->Enabled = true;
8728  if(Track->IsTrackFinished())
8729  SelectLengthsMenuItem->Enabled = true; // only permit if finished because reverts to DistanceStart
8730  else
8731  SelectLengthsMenuItem->Enabled = false; // and that can only be used if track linked
8732  SelectBiDirPrefDirsMenuItem->Visible = false;
8733  CancelSelectionMenuItem->Enabled = true;
8734  mbLeftDown = false;
8735  // Level1Mode = TrackMode;
8736  // SetLevel1Mode(68);
8738  SetLevel2TrackMode(47);
8739  Utilities->CallLogPop(1425);
8740  }
8741  catch(const Exception &e)
8742  {
8743  ErrorLog(146, e.Message);
8744  }
8745 }
8746 
8747 // ---------------------------------------------------------------------------
8748 void __fastcall TInterface::CutMenuItemClick(TObject *Sender)
8749 {
8750  try
8751  {
8752  TrainController->LogEvent("CutMenuItemClick");
8753  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CutMenuItemClick");
8754  // Level1Mode = TrackMode;
8755  // SetLevel1Mode(69);
8757  SetLevel2TrackMode(35);
8758  Utilities->CallLogPop(1190);
8759  }
8760  catch(const Exception &e)
8761  {
8762  ErrorLog(147, e.Message);
8763  }
8764 }
8765 // ---------------------------------------------------------------------------
8766 
8767 void __fastcall TInterface::CopyMenuItemClick(TObject *Sender)
8768 {
8769  try
8770  {
8771  TrainController->LogEvent("CopyMenuItemClick");
8772  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CopyMenuItemClick");
8773  // Level1Mode = TrackMode;
8774  // SetLevel1Mode(70);
8776  SetLevel2TrackMode(36);
8777  Utilities->CallLogPop(1191);
8778  }
8779  catch(const Exception &e)
8780  {
8781  ErrorLog(148, e.Message);
8782  }
8783 }
8784 
8785 // ---------------------------------------------------------------------------
8786 void __fastcall TInterface::FlipMenuItemClick(TObject *Sender)
8787 {
8788  try
8789  {
8790  TrainController->LogEvent("FlipMenuItemClick");
8791  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FlipMenuItemClick");
8792  // reset values in SelectVector
8793  int VerSum = SelectRect.top + SelectRect.bottom - 1;
8794  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
8795  {
8796  // Note: (changed again in v2.4.0 to keep attributes) need to change flip, mirror & 180deg functions as only change speedtag without changing anything else.
8797  // This didn't matter before new paste with attributes added at v2.2.0 as a new element was built from the speedtag,
8798  // but now if do a reselect then cut and paste with attributes the wrong graphic is pasted and all other attributes
8799  // are wrong. Need to rebuild a new TrackElement from the new speedtag and use that in the select vector.
8800  // Note that if use Flip, mirror etc then all attributes lost anyway so ok to build a basic element.
8801  int VLoc = VerSum - Track->SelectVectorAt(8, x).VLoc;
8802  int HLoc = Track->SelectVectorAt(7, x).HLoc;
8804  TE.VLoc = VLoc;
8805  TE.HLoc = HLoc;
8806 
8807  TE.ActiveTrackElementName = Track->SelectVectorAt(37, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
8809  TE.Length01 = Track->SelectVectorAt(39, x).Length01;
8810  TE.Length23 = Track->SelectVectorAt(40, x).Length23;
8813  TE.SigAspect = Track->SelectVectorAt(43, x).SigAspect;
8814  Track->SelectVectorAt(26, x) = TE;
8815  }
8816  // reset values in SelectTextVector
8817  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(0); x++)
8818  {
8820  // also subtract font height, brings position approximately right
8821  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
8822  }
8823  // reset values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
8824  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8825  {
8826  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
8827  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
8828  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
8829  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
8830  }
8832  SetLevel2TrackMode(48);
8833  Utilities->CallLogPop(1426);
8834  }
8835  catch(const Exception &e)
8836  {
8837  ErrorLog(149, e.Message);
8838  }
8839 }
8840 
8841 // ---------------------------------------------------------------------------
8842 void __fastcall TInterface::MirrorMenuItemClick(TObject *Sender)
8843 {
8844  try
8845  {
8846  TrainController->LogEvent("MirrorMenuItemClick");
8847  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MirrorMenuItemClick");
8848  // reset values in SelectVector
8849  int HorSum = SelectRect.left + SelectRect.right - 1;
8850  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
8851  {
8852  // See note above for FlipMenuItem relating to mods for v2.2.0
8853  int VLoc = Track->SelectVectorAt(22, x).VLoc;
8854  int HLoc = HorSum - Track->SelectVectorAt(6, x).HLoc;
8856  TE.VLoc = VLoc;
8857  TE.HLoc = HLoc;
8858 
8859  TE.ActiveTrackElementName = Track->SelectVectorAt(44, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
8861  TE.Length01 = Track->SelectVectorAt(46, x).Length01;
8862  TE.Length23 = Track->SelectVectorAt(47, x).Length23;
8865  TE.SigAspect = Track->SelectVectorAt(50, x).SigAspect;
8866 
8867 // if(Track->SelectVectorAt(28, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(29, x).SigAspect;//TrackType will be the same
8868  Track->SelectVectorAt(30, x) = TE;
8869 // Track->SelectVectorAt(, x).HLoc = HorSum - Track->SelectVectorAt(, x).HLoc;
8870 // Track->SelectVectorAt(, x).SpeedTag = Track->MirrorArray[Track->SelectVectorAt(, x).SpeedTag];
8871  }
8872  // reset values in SelectTextVector
8873  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(1); x++)
8874  {
8876  // also subtract half font height for each letter of text, brings position approximately right
8877  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
8878  }
8879  // reset values in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
8880  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8881  {
8882  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
8883  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
8884  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
8885  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
8886  {
8887  LeftPosAfterMirror = SelectRect.left * 16;
8888  }
8889  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
8890  }
8892  SetLevel2TrackMode(49);
8893  Utilities->CallLogPop(1427);
8894  }
8895  catch(const Exception &e)
8896  {
8897  ErrorLog(150, e.Message);
8898  }
8899 }
8900 
8901 // ---------------------------------------------------------------------------
8902 void __fastcall TInterface::RotateMenuItemClick(TObject *Sender)
8903 {
8904  try
8905  {
8906  TrainController->LogEvent("Rotate180MenuItemClick");
8907  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",Rotate180MenuItemClick");
8908  // reset values in SelectVector
8909  int HorSum = SelectRect.left + SelectRect.right - 1;
8910  int VerSum = SelectRect.top + SelectRect.bottom - 1;
8911  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
8912  {
8913  // See note above for FlipMenuItem relating to mods for v2.2.0
8914  int VLoc = VerSum - Track->SelectVectorAt(23, x).VLoc;
8915  int HLoc = HorSum - Track->SelectVectorAt(36, x).HLoc;
8917  TE.VLoc = VLoc;
8918  TE.HLoc = HLoc;
8919 
8920  TE.ActiveTrackElementName = Track->SelectVectorAt(51, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
8922  TE.Length01 = Track->SelectVectorAt(53, x).Length01;
8923  TE.Length23 = Track->SelectVectorAt(54, x).Length23;
8926  TE.SigAspect = Track->SelectVectorAt(57, x).SigAspect;
8927 
8928 // if(Track->SelectVectorAt(32, x).TrackType == SignalPost) TE.SigAspect = Track->SelectVectorAt(33, x).SigAspect; dropped in v2.4.0 for above
8929  Track->SelectVectorAt(34, x) = TE;
8930 // TTrackElement &TempEl = Track->SelectVectorAt(13, x);
8931 // TempEl.HLoc = HorSum - TempEl.HLoc;
8932 // TempEl.VLoc = VerSum - TempEl.VLoc;
8933 // TempEl.SpeedTag = Track->MirrorArray[Track->FlipArray[TempEl.SpeedTag]];
8934  }
8935  // reset values in SelectTextVector
8936  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(2); x++)
8937  {
8939  // also subtract half font height for each letter of text, brings position approximately right horizontally
8940  TextItem->HPos = ((HorSum * 16) + 15) - TextItem->HPos - (TextItem->TextString.Length() * 0.5 * abs(TextItem->Font->Height));
8941  // also subtract font height, brings position approximately right vertically
8942  TextItem->VPos = ((VerSum * 16) + 15) - TextItem->VPos - abs(TextItem->Font->Height);
8943  }
8944  // reset flip values in SelectGraphicVector so the midpoint of the graphic flips about the midline of the selection
8945  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8946  {
8947  int MidVPosBeforeFlip = Track->SelectGraphicVector.at(x).VPos + (Track->SelectGraphicVector.at(x).Height) / 2;
8948  int MidVPosAfterFlip = ((VerSum * 16) + 15) - MidVPosBeforeFlip;
8949  int TopPosAfterFlip = MidVPosAfterFlip - (Track->SelectGraphicVector.at(x).Height) / 2;
8950  if(TopPosAfterFlip < (SelectRect.top * 16)) // shouldn't go above top but check
8951  {
8952  TopPosAfterFlip = SelectRect.top * 16;
8953  }
8954  Track->SelectGraphicVector.at(x).VPos = TopPosAfterFlip;
8955  }
8956  // reset mirror in SelectGraphicVector so the midpoint of the graphic mirrors about the midline of the selection
8957  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
8958  {
8959  int MidHPosBeforeMirror = Track->SelectGraphicVector.at(x).HPos + (Track->SelectGraphicVector.at(x).Width) / 2;
8960  int MidHPosAfterMirror = ((HorSum * 16) + 15) - MidHPosBeforeMirror;
8961  int LeftPosAfterMirror = MidHPosAfterMirror - (Track->SelectGraphicVector.at(x).Width) / 2;
8962  if(LeftPosAfterMirror < (SelectRect.left * 16)) // shouldn't go below left but check
8963  {
8964  LeftPosAfterMirror = SelectRect.left * 16;
8965  }
8966  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterMirror;
8967  }
8968  // Level1Mode = TrackMode;
8969  // SetLevel1Mode(73);
8971  SetLevel2TrackMode(50);
8972  Utilities->CallLogPop(1435);
8973  }
8974  catch(const Exception &e)
8975  {
8976  ErrorLog(151, e.Message);
8977  }
8978 }
8979 // ---------------------------------------------------------------------------
8980 
8981 void __fastcall TInterface::RotRightMenuItemClick(TObject *Sender)
8982 {
8983  try
8984  {
8985  TrainController->LogEvent("RotateRight90MenuItemClick");
8986  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateRight90MenuItemClick");
8987  Screen->Cursor = TCursor(-11); // Hourglass
8988  // check first if a square and if not give message & quit
8989  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
8990  {
8991  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
8992  int VertSize = SelectRect.bottom - SelectRect.top;
8993  if((SelectRect.Left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
8994  {
8995  // use right hand vertical & make square to left of that
8996  SelectRect.left = SelectRect.right - VertSize;
8997  }
8998  else
8999  {
9000  SelectRect.right = SelectRect.left + VertSize;
9001  }
9004  int button = Application->MessageBox
9005  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
9006  L"Left click and hold here to move this message box", MB_OKCANCEL);
9007  if(button == IDCANCEL)
9008  {
9009  ResetSelectRect();
9010  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
9011  SetLevel1Mode(133);
9013  SetLevel2TrackMode(59);
9015  Screen->Cursor = TCursor(-2); // Arrow
9016  Utilities->CallLogPop(2121);
9017  return;
9018  }
9019  }
9020  // set SelectBitmap (only need the dimensions here as not moving the selection)
9023  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
9024  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
9025  // store track elements and text in select vectors
9027  TTrackElement TempElement; // default element
9028  bool FoundFlag;
9029  for(int x = SelectRect.left; x < SelectRect.right; x++)
9030  {
9031  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9032  {
9033  int ATVecPos = Track->GetVectorPositionFromTrackMap(57, x, y, FoundFlag);
9034  if(FoundFlag)
9035  {
9036  TempElement = Track->TrackElementAt(959, ATVecPos);
9037  if(TempElement.SpeedTag > 0)
9038  Track->SelectPush(TempElement);
9039  }
9040  }
9041  }
9042  // now store inactive elements
9043  for(int x = SelectRect.left; x < SelectRect.right; x++)
9044  {
9045  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9046  {
9047  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(28, x, y, FoundFlag);
9048  if(FoundFlag)
9049  {
9050  TempElement = Track->InactiveTrackElementAt(126, IATVecPair.first);
9051  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
9052  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
9053  {
9054  TempElement = Track->InactiveTrackElementAt(127, IATVecPair.second);
9055  Track->SelectPush(TempElement);
9056  }
9057  }
9058  }
9059  }
9060  // store text items
9061  int LowSelectHPos = SelectRect.left * 16;
9062  int HighSelectHPos = SelectRect.right * 16;
9063  int LowSelectVPos = SelectRect.top * 16;
9064  int HighSelectVPos = SelectRect.bottom * 16;
9065  TextHandler->SelectTextVector.clear();
9066  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
9067  {
9068  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
9069  {
9070  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
9071  {
9072  // have to create a new TextItem in order to create a new Font object
9073  // BUT: only create new items where they don't appear as named location names
9074  // in SelectVector, since those names shouldn't be copied or pasted.
9075  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
9076  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
9077  bool SelectVectorNamedElement = false;
9078  AnsiString SelectTextString; // new at v2.2.0
9079  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
9080  {
9081  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
9082  {
9083  SelectVectorNamedElement = true;
9084  break;
9085  }
9086  }
9087  if(SelectVectorNamedElement) // changed at v2.2.0
9088  {
9089  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
9090  }
9091  else // new at v2.2.0
9092  {
9093  SelectTextString = TextPtr->TextString;
9094  }
9095  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
9096  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
9097  }
9098  }
9099  }
9100  // store graphic items, but first clear SelectGraphicVector
9101  Track->SelectGraphicVector.clear();
9102  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
9103  {
9104  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
9105  UserGraphicPtr++)
9106  {
9107  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
9108  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
9109  {
9110  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
9111  }
9112  }
9113  }
9114  // now transform the H & V for rh rotate
9115  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9116  {
9117  int HLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(74, x).VLoc;
9118  int VLoc = SelectRect.top - SelectRect.left + Track->SelectVectorAt(75, x).HLoc;
9120  TE.VLoc = VLoc;
9121  TE.HLoc = HLoc;
9122 
9123  TE.ActiveTrackElementName = Track->SelectVectorAt(58, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9125  TE.Length01 = Track->SelectVectorAt(60, x).Length01;
9126  TE.Length23 = Track->SelectVectorAt(61, x).Length23;
9129  TE.SigAspect = Track->SelectVectorAt(64, x).SigAspect;
9130  Track->SelectVectorAt(65, x) = TE;
9131  }
9132  // reset values in SelectTextVector
9133  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(3); x++)
9134  {
9135 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
9136 // & if a lot then some will extend beyond the selection
9138  // also subtract half font height for each letter of text, brings position approximately right horizontally
9139  TextItem->HPos = (SelectRect.left) * 16;
9140  TextItem->VPos = (SelectRect.top + x) * 16;
9141  }
9142  // reset values in SelectGraphicVector
9143  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9144  {
9145  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
9146  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
9147  int MidHPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidVPosBeforeRotate;
9148  int MidVPosAfterRotate = ((SelectRect.top - SelectRect.left) * 16) + MidHPosBeforeRotate;
9149  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
9150  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
9151  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
9152  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
9153  }
9154  Screen->Cursor = TCursor(-2); // Arrow
9156  SetLevel2TrackMode(60);
9157  Utilities->CallLogPop(2122);
9158  }
9159  catch(const Exception &e)
9160  {
9161  ErrorLog(205, e.Message);
9162  }
9163 }
9164 
9165 // ---------------------------------------------------------------------------
9166 
9167 void __fastcall TInterface::RotLeftMenuItemClick(TObject *Sender)
9168 {
9169  try
9170  {
9171  TrainController->LogEvent("RotateLeft90MenuItemClick");
9172  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RotateLeft90MenuItemClick");
9173  Screen->Cursor = TCursor(-11); // Hourglass;
9174  // check first if a square and if not give message & quit
9175  if((SelectRect.right - SelectRect.left) != (SelectRect.bottom - SelectRect.top))
9176  {
9177  // use left vertical side to make square & keep top lh corner unless rhs would exceed display, in which case use the right vertical & keep to rh corner
9178  int VertSize = SelectRect.bottom - SelectRect.top;
9179  if((SelectRect.Left + VertSize - Display->DisplayOffsetH) > Utilities->ScreenElementWidth)
9180  {
9181  // use right hand vertical & make square to left of that
9182  SelectRect.left = SelectRect.right - VertSize;
9183  }
9184  else
9185  {
9186  SelectRect.right = SelectRect.left + VertSize;
9187  }
9190  int button = Application->MessageBox
9191  (L"Original selection adjusted to make it square. 'OK' to keep this selection or 'Cancel' to make a new selection",
9192  L"Left click and hold here to move this message box", MB_OKCANCEL);
9193  if(button == IDCANCEL)
9194  {
9195  ResetSelectRect();
9196  Level1Mode = TrackMode; // call this first to clear everything, then set PrefDir mode
9197  SetLevel1Mode(134);
9199  SetLevel2TrackMode(61);
9201  Screen->Cursor = TCursor(-2); // Arrow
9202  Utilities->CallLogPop(2123);
9203  return;
9204  }
9205  }
9206  // set SelectBitmap (only need the dimensions here as not moving the selection)
9209  SelectBitmap->Width = (SelectRect.right - SelectRect.left) * 16;
9210  SelectBitmap->Height = (SelectRect.bottom - SelectRect.top) * 16;
9211  // store track elements and text in select vectors
9213  TTrackElement TempElement; // default element
9214  bool FoundFlag;
9215  for(int x = SelectRect.left; x < SelectRect.right; x++)
9216  {
9217  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9218  {
9219  int ATVecPos = Track->GetVectorPositionFromTrackMap(58, x, y, FoundFlag);
9220  if(FoundFlag)
9221  {
9222  TempElement = Track->TrackElementAt(960, ATVecPos);
9223  if(TempElement.SpeedTag > 0)
9224  Track->SelectPush(TempElement);
9225  }
9226  }
9227  }
9228  // now store inactive elements
9229  for(int x = SelectRect.left; x < SelectRect.right; x++)
9230  {
9231  for(int y = SelectRect.top; y < SelectRect.bottom; y++)
9232  {
9233  TTrack::TIMPair IATVecPair = Track->GetVectorPositionsFromInactiveTrackMap(29, x, y, FoundFlag);
9234  if(FoundFlag)
9235  {
9236  TempElement = Track->InactiveTrackElementAt(128, IATVecPair.first);
9237  Track->SelectPush(TempElement); // only want SpeedTag & location set, rest defaults
9238  if(IATVecPair.second != IATVecPair.first) // 2 elements stored at location, i.e. platforms
9239  {
9240  TempElement = Track->InactiveTrackElementAt(129, IATVecPair.second);
9241  Track->SelectPush(TempElement);
9242  }
9243  }
9244  }
9245  }
9246  // store text items
9247  int LowSelectHPos = SelectRect.left * 16;
9248  int HighSelectHPos = SelectRect.right * 16;
9249  int LowSelectVPos = SelectRect.top * 16;
9250  int HighSelectVPos = SelectRect.bottom * 16;
9251  TextHandler->SelectTextVector.clear();
9252  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
9253  {
9254  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->TextVector.begin(); TextPtr < TextHandler->TextVector.end(); TextPtr++)
9255  {
9256  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos < HighSelectVPos))
9257  {
9258  // have to create a new TextItem in order to create a new Font object
9259  // BUT: only create new items where they don't appear as named location names
9260  // in SelectVector, since those names shouldn't be copied or pasted.
9261  // NB: altered for PasteWithAttributes - at v2.2.0 save the named element but prefix it with "##**"
9262  // so can paste or not depending on which type of paste is being used (unlikely to use that in a real name)
9263  bool SelectVectorNamedElement = false;
9264  AnsiString SelectTextString; // new at v2.2.0
9265  for(unsigned int x = 0; x < Track->SelectVector.size(); x++)
9266  {
9267  if(Track->SelectVector.at(x).LocationName == TextPtr->TextString)
9268  {
9269  SelectVectorNamedElement = true;
9270  break;
9271  }
9272  }
9273  if(SelectVectorNamedElement) // changed at v2.2.0
9274  {
9275  SelectTextString = "##**" + TextPtr->TextString; // new at v2.2.0
9276  }
9277  else // new at v2.2.0
9278  {
9279  SelectTextString = TextPtr->TextString;
9280  }
9281  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, SelectTextString, TextPtr->Font);
9282  TextHandler->SelectTextVector.push_back(TextItem); // changed at v2.2.0
9283  }
9284  }
9285  }
9286  // store graphic items, but first clear SelectGraphicVector
9287  Track->SelectGraphicVector.clear();
9288  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
9289  {
9290  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = Track->UserGraphicVector.begin(); UserGraphicPtr < Track->UserGraphicVector.end();
9291  UserGraphicPtr++)
9292  {
9293  if((UserGraphicPtr->HPos >= LowSelectHPos) && ((UserGraphicPtr->HPos + UserGraphicPtr->Width) < HighSelectHPos) && (UserGraphicPtr->VPos >=
9294  LowSelectVPos) && ((UserGraphicPtr->VPos + UserGraphicPtr->Height) < HighSelectVPos))
9295  {
9296  Track->SelectGraphicVector.push_back(*UserGraphicPtr);
9297  }
9298  }
9299  }
9300  // now transform the H & V for lh rotate
9301  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9302  {
9303  int HLoc = SelectRect.left - SelectRect.top + Track->SelectVectorAt(76, x).VLoc;
9304  int VLoc = SelectRect.bottom - 1 + SelectRect.left - Track->SelectVectorAt(77, x).HLoc;
9306  TE.VLoc = VLoc;
9307  TE.HLoc = HLoc;
9308 
9309  TE.ActiveTrackElementName = Track->SelectVectorAt(66, x).ActiveTrackElementName; // these new in v2.4.0 so keeps attributes
9311  TE.Length01 = Track->SelectVectorAt(68, x).Length01;
9312  TE.Length23 = Track->SelectVectorAt(69, x).Length23;
9315  TE.SigAspect = Track->SelectVectorAt(72, x).SigAspect;
9316  Track->SelectVectorAt(73, x) = TE;
9317  }
9318  // reset values in SelectTextVector
9319  for(unsigned int x = 0; x < TextHandler->SelectTextVectorSize(4); x++)
9320  {
9321 // no point trying to locate text properly as it stays horizontal so will always be wrongly placed, just list all itels vertically at lhs
9322 // & if a lot then some will extend beyond the selection
9324  // also subtract half font height for each letter of text, brings position approximately right horizontally
9325  TextItem->HPos = (SelectRect.left) * 16;
9326  TextItem->VPos = (SelectRect.top + x) * 16;
9327  }
9328  // reset values in SelectGraphicVector
9329  for(unsigned int x = 0; x < Track->SelectGraphicVector.size(); x++)
9330  {
9331  int MidHPosBeforeRotate = Track->SelectGraphicVector.at(x).HPos + Track->SelectGraphicVector.at(x).Width / 2;
9332  int MidVPosBeforeRotate = Track->SelectGraphicVector.at(x).VPos + Track->SelectGraphicVector.at(x).Height / 2;
9333  int MidHPosAfterRotate = ((SelectRect.left - SelectRect.top) * 16) + MidVPosBeforeRotate;
9334  int MidVPosAfterRotate = ((SelectRect.bottom * 16) - 1) + (SelectRect.left * 16) - MidHPosBeforeRotate;
9335  int LeftPosAfterRotate = MidHPosAfterRotate - (Track->SelectGraphicVector.at(x).Width) / 2;
9336  int TopPosAfterRotate = MidVPosAfterRotate - (Track->SelectGraphicVector.at(x).Height) / 2;
9337  Track->SelectGraphicVector.at(x).HPos = LeftPosAfterRotate;
9338  Track->SelectGraphicVector.at(x).VPos = TopPosAfterRotate;
9339  }
9340  Screen->Cursor = TCursor(-2); // Arrow
9342  SetLevel2TrackMode(62);
9343  Utilities->CallLogPop(2124);
9344  }
9345  catch(const Exception &e)
9346  {
9347  ErrorLog(206, e.Message);
9348  }
9349 }
9350 
9351 // ---------------------------------------------------------------------------
9352 
9353 void __fastcall TInterface::PasteMenuItemClick(TObject *Sender)
9354 {
9355  try
9356  {
9357  TrainController->LogEvent("PasteMenuItemClick");
9358  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PasteMenuItemClick");
9359  // Level1Mode = TrackMode;
9360  // SetLevel1Mode(74);
9362  SetLevel2TrackMode(58);
9363  Utilities->CallLogPop(2060);
9364  }
9365  catch(const Exception &e)
9366  {
9367  ErrorLog(198, e.Message);
9368  }
9369 }
9370 
9371 // ---------------------------------------------------------------------------
9372 void __fastcall TInterface::DeleteMenuItemClick(TObject *Sender)
9373 {
9374  try
9375  {
9376  TrainController->LogEvent("DeleteMenuItemClick");
9377  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",DeleteMenuItemClick");
9378  // Level1Mode = TrackMode;
9379  // SetLevel1Mode(75);
9381  SetLevel2TrackMode(38);
9382  Utilities->CallLogPop(1193);
9383  }
9384  catch(const Exception &e)
9385  {
9386  ErrorLog(153, e.Message);
9387  }
9388 }
9389 // ---------------------------------------------------------------------------
9390 
9391 void __fastcall TInterface::SelectLengthsMenuItemClick(TObject *Sender)
9392 {
9393  try
9394  {
9395  TrainController->LogEvent("SelectLengthsMenuItemClick");
9396  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectLengthsMenuItemClick");
9397  TrackElementPanel->Visible = false;
9398  TrackLengthPanel->Visible = true;
9399  TrackLengthPanel->SetFocus();
9400  SelectLengthsFlag = true;
9401  InfoPanel->Visible = true;
9402  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Set values or leave blank for no change";
9403  ShowMessage("Note: length value will apply to each element's track within the selection");
9404  DistanceBox->Text = "";
9405  SpeedLimitBox->Text = "";
9408  ResetChangedFileDataAndCaption(19, true); // true for NonPrefDirChangesMade
9409  Utilities->CallLogPop(1414);
9410  }
9411  catch(const Exception &e)
9412  {
9413  ErrorLog(154, e.Message);
9414  }
9415 }
9416 
9417 // ---------------------------------------------------------------------------
9418 
9419 void __fastcall TInterface::SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
9420 {
9421 /* SelectVector contains all the track elements (and inactive elements but don't need them), so create up to 4 PrefDir
9422  elements from each one, and add each into ConstructPrefDir, then when all added use ConsolidatePrefDirs to add to EveryPrefDir
9423 */
9424  try
9425  {
9426  TrainController->LogEvent("SelectBiDirPrefDirsMenuItemClick");
9427  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectBiDirPrefDirsMenuItemClick");
9429  bool FoundFlag = false;
9430  if(Track->SelectVector.empty())
9431  {
9432  Utilities->CallLogPop(1550);
9433  return;
9434  }
9435  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
9436  {
9437  TTrackElement TE = Track->SelectVectorAt(14, x);
9438  int VecPos = Track->GetVectorPositionFromTrackMap(42, TE.HLoc, TE.VLoc, FoundFlag);
9439  if(FoundFlag)
9440  {
9441  if((TE.TrackType == Points) || (TE.TrackType == Bridge) || (TE.TrackType == Crossover)) // 2-track element
9442  {
9443  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
9445  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
9447  TPrefDirElement PE2(TE, TE.Link[2], 2, TE.Link[3], 3, VecPos);
9449  TPrefDirElement PE3(TE, TE.Link[3], 3, TE.Link[2], 2, VecPos);
9451  }
9452  else if((TE.TrackType == Simple) || (TE.TrackType == Buffers) || (TE.TrackType == SignalPost) || (TE.TrackType == Continuation) ||
9453  (TE.TrackType == GapJump) || (TE.TrackType == FootCrossing))
9454  // need to list these explicitly since inactive elements will still be 'found' if there is an active element
9455  // at the same position
9456  {
9457  TPrefDirElement PE0(TE, TE.Link[0], 0, TE.Link[1], 1, VecPos);
9459  TPrefDirElement PE1(TE, TE.Link[1], 1, TE.Link[0], 0, VecPos);
9461  }
9462  }
9463  }
9465  ResetChangedFileDataAndCaption(22, false);
9466  // RlyFile = false; - don't alter this just for PrefDir changes
9467  Level1Mode = BaseMode; // call this first to clear everything, then set PrefDir mode
9468  SetLevel1Mode(30);
9470  SetLevel1Mode(31); // calls Clearand... to display all PrefDirs
9471  Utilities->CallLogPop(1549);
9472  }
9473  catch(const Exception &e)
9474  {
9475  ErrorLog(155, e.Message);
9476  }
9477 }
9478 
9479 // ---------------------------------------------------------------------------
9480 void __fastcall TInterface::CancelSelectionMenuItemClick(TObject *Sender)
9481 {
9482  try
9483  {
9484  TrainController->LogEvent("CancelSelectionClick");
9485  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CancelSelectionClick");
9486  ClearandRebuildRailway(46); // to remove the selection outline
9487  SelectionValid = false;
9488  Track->CopyFlag = false;
9490  ResetSelectRect();
9491  if(Level1Mode == TrackMode)
9492  {
9493  SetLevel1Mode(76);
9495  SetLevel2TrackMode(39);
9496  }
9497  else if(Level1Mode == PrefDirMode)
9498  {
9499  SetLevel1Mode(32);
9500  }
9501  Utilities->CallLogPop(1413);
9502  }
9503  catch(const Exception &e)
9504  {
9505  ErrorLog(156, e.Message);
9506  }
9507 }
9508 
9509 // ---------------------------------------------------------------------------
9510 void __fastcall TInterface::LoadTimetableMenuItemClick(TObject *Sender)
9511 {
9512  try
9513  {
9514  TrainController->LogEvent("LoadTimetableMenuItemClick");
9515  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LoadTimetableMenuItemClick");
9516  TimetableDialog->Filter = "Timetable file (*.ttb)|*.ttb";
9517  // reset all message flags, stops them being given twice new at v2.4.0
9518  TrainController->SSHigh = false;
9519  TrainController->MRSHigh = false;
9520  TrainController->MRSLow = false;
9521  TrainController->MassHigh = false;
9522  TrainController->BFHigh = false;
9523  TrainController->BFLow = false;
9524  TrainController->PwrHigh = false;
9525  TrainController->SigSHigh = false;
9526  TrainController->SigSLow = false;
9527  if(TimetableDialog->Execute())
9528  {
9529  TrainController->LogEvent("LoadTimetable " + TimetableDialog->FileName);
9530  bool CheckLocationsExistInRailwayTrue = true;
9531  if(TrainController->TimetableIntegrityCheck(0, AnsiString(TimetableDialog->FileName).c_str(), true, CheckLocationsExistInRailwayTrue))
9532  // true for GiveMessages
9533  {
9534  Screen->Cursor = TCursor(-11); // Hourglass;
9535  std::ifstream TTBLFile(AnsiString(TimetableDialog->FileName).c_str(), std::ios_base::binary);
9536  if(TTBLFile.is_open())
9537  {
9538  bool SessionFileFalse = false;
9539  if(BuildTrainDataVectorForLoadFile(0, TTBLFile, true, CheckLocationsExistInRailwayTrue, SessionFileFalse)) // true for GiveMessages
9540  {
9541  SaveTempTimetableFile(0, TimetableDialog->FileName);
9542  } // don't need an 'else' as messages given in BuildTrainDataVectorForLoadFile
9543  }
9544  else
9545  {
9546  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
9547  }
9548  Screen->Cursor = TCursor(-2); // Arrow
9549  } // if(TimetableIntegrityCheck
9550  else
9551  ShowMessage("Timetable preliminary integrity check failed - unable to load");
9552  } // if(TimetableDialog->Execute())
9553  // else ShowMessage("Load Aborted");
9554  Utilities->CallLogPop(752);
9555  }
9556  catch(const Exception &e)
9557  {
9558  ErrorLog(34, e.Message);
9559  }
9560 }
9561 
9562 // ---------------------------------------------------------------------------
9563 void __fastcall TInterface::TakeSignallerControlMenuItemClick(TObject *Sender)
9564 {
9565  try
9566  {
9567  TrainController->LogEvent("SignallerControl1Click");
9568  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControl1Click");
9570  Train.SignallerStoppingFlag = false;
9571  Train.TrainMode = Signaller;
9572  if(Train.MaxRunningSpeed > Train.SignallerMaxSpeed)
9573  {
9574  Train.MaxRunningSpeed = Train.SignallerMaxSpeed;
9575  }
9576  if(Train.Stopped())
9577  Train.SignallerStopped = true; // condition added at v2.4.0 to allow for taking sig control of failed moving trains
9578  Train.CallingOnFlag = false; // in case was set, wouldn't start anyway if called on as SignallerStopped = true
9580  Train.PlotTrain(5, Display);
9581  AnsiString LocName = "";
9582  if(Train.LeadElement > -1)
9583  {
9584  LocName = Track->TrackElementAt(633, Train.LeadElement).ActiveTrackElementName;
9585  }
9586  if((LocName == "") && (Train.MidElement > -1))
9587  {
9588  LocName = Track->TrackElementAt(634, Train.MidElement).ActiveTrackElementName;
9589  }
9590 
9591  // store the value that allow restoration of tt control or not - RestoreTimetableLocation
9592  if(Train.StoppedAtLocation && (LocName != ""))
9593  {
9594  Train.RestoreTimetableLocation = LocName;
9595  }
9596  else
9597  {
9598  Train.RestoreTimetableLocation = "";
9599  }
9600 
9601  // check whether need to offer 'pass red signal'
9602  if(!Train.StoppedAtSignal && Train.StoppedAtLocation)
9603  {
9604  int NextElementPosition = Track->TrackElementAt(775, Train.LeadElement).Conn[Train.LeadExitPos];
9605  int NextEntryPos = Track->TrackElementAt(776, Train.LeadElement).ConnLinkPos[Train.LeadExitPos];
9606  if((NextElementPosition > -1) && (NextEntryPos > -1))
9607  {
9608  if((Track->TrackElementAt(777, NextElementPosition).Config[Track->GetNonPointsOppositeLinkPos(NextEntryPos)] == Signal) &&
9609  (Track->TrackElementAt(778, NextElementPosition).Attribute == 0))
9610  { // set both StoppedAtLocation & StoppedAtSignal, so that 'pass red signal' is offered in popup menu rather than move
9611  // forwards, but don't change the background colour so still shows as stopped at location
9612  Train.StoppedAtSignal = true;
9613  }
9614  }
9615  }
9616  // find element ID if no locname
9617  if((LocName == "") && Train.LeadElement > -1)
9618  {
9619  LocName = Track->TrackElementAt(635, Train.LeadElement).ElementID;
9620  }
9621  if((LocName == "") && (Train.MidElement > -1))
9622  {
9623  LocName = Track->TrackElementAt(636, Train.MidElement).ElementID;
9624  }
9625  Train.LogAction(0, Train.HeadCode, "", TakeSignallerControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9626  Utilities->CallLogPop(1772);
9627  }
9628  catch(const Exception &e)
9629  {
9630  ErrorLog(157, e.Message);
9631  }
9632 }
9633 
9634 // ---------------------------------------------------------------------------
9635 
9636 void __fastcall TInterface::TimetableControlMenuItemClick(TObject *Sender)
9637 {
9638  try
9639  {
9640  TrainController->LogEvent("TimetableControlMenuItemClick");
9641  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TimetableControlMenuItemClick");
9643  Train.SignallerStoppingFlag = false;
9644  Train.TrainMode = Timetable;
9645  Train.SignallerStopped = false;
9646  Train.StoppedAfterSPAD = false;
9647  Train.SPADFlag = false;
9650 // red headcode[0]
9651  Train.PlotTrain(6, Display);
9652  AnsiString LocName = "";
9653  if(Train.LeadElement > -1)
9654  {
9655  LocName = Track->TrackElementAt(645, Train.LeadElement).ActiveTrackElementName;
9656  }
9657  if((LocName == "") && (Train.MidElement > -1))
9658  {
9659  LocName = Track->TrackElementAt(647, Train.MidElement).ActiveTrackElementName;
9660  }
9661  if((LocName == "") && Train.LeadElement > -1)
9662  {
9663  LocName = Track->TrackElementAt(646, Train.LeadElement).ElementID;
9664  }
9665  if((LocName == "") && (Train.MidElement > -1))
9666  {
9667  LocName = Track->TrackElementAt(648, Train.MidElement).ElementID;
9668  }
9669  if((Train.ActionVectorEntryPtr->LocationType == AtLocation) && (LocName == Train.ActionVectorEntryPtr->LocationName))
9670  {
9671  Train.StoppedAtLocation = true;
9672  Train.LastActionTime = TrainController->TTClockTime; // by itself this only affects trains that have still to arrive, if waiting to
9673  // depart the departure time & TRS time have already been calculated so need to
9674  // force a recalculation - see below
9675  Train.DepartureTimeSet = false; // force it to be recalculated based on new LastActionTime (if waiting to arrive this is false anyway)
9676  if(!Train.TrainFailed)
9677  {
9679  }
9680  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9681  if((Train.ActionVectorEntryPtr->FormatType == TimeLoc) && (Train.ActionVectorEntryPtr->ArrivalTime >= TDateTime(0)))
9682  { // Timetable indicates that train still waiting to arrive for a TimeLoc arrival so send message and mark as arrived
9683  Train.LogAction(28, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
9684  Train.ActionVectorEntryPtr++; // advance pointer past arrival //added at v1.2.0
9685  }
9686  else if((Train.ActionVectorEntryPtr->FormatType == TimeTimeLoc) && !(Train.TimeTimeLocArrived))
9687  { // Timetable indicates that train still waiting to arrive for a TimeTimeLoc arrival so send message and mark as arrived
9688  Train.LogAction(29, Train.HeadCode, "", Arrive, LocName, Train.ActionVectorEntryPtr->ArrivalTime, Train.ActionVectorEntryPtr->Warning);
9689  Train.TimeTimeLocArrived = true;
9690  // NB: No need for 'Train.ActionVectorEntryPtr++' because still to act on the departure time
9691  }
9692  }
9693  else
9694  {
9695  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas error
9696  int NextEntryPos = -1; // ---ditto---
9697  if(Train.LeadElement > -1) // ---ditto---
9698  { // ---ditto---
9699  NextElementPos = Track->TrackElementAt(658, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
9700  NextEntryPos = Track->TrackElementAt(659, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
9701  } // ---ditto---
9702  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9703  if(!Train.TrainFailed)
9704  {
9705  Train.PlotTrainWithNewBackgroundColour(31, clNormalBackground, Display); // to remove other background if was present, moved from
9706  } // within Train.AbleToMove at v2.4.0 to cancel signal stop background
9707  if(Train.AbleToMove(1)) // if has no power
9708  {
9709  Train.EntrySpeed = 0; // moved from below for v1.3.2 after Carwyn Thomas error
9710  Train.EntryTime = TrainController->TTClockTime; // ---Ditto---
9711  Train.FirstHalfMove = true; // ---Ditto---
9712  if((NextElementPos > -1) && (NextEntryPos > -1)) // changed from if(NextElementPos >= 0) as above
9713  {
9714  // Train.EntrySpeed = 0;
9715  // Train.EntryTime = TrainController->TTClockTime;
9716  // Train.FirstHalfMove = true;
9717  Train.SetTrainMovementValues(15, NextElementPos, NextEntryPos);
9718  }
9719  // else follow the continuations //added these 3 conditions for v1.3.2 after Carwyn Thomas error
9720  else if((Train.LeadElement > -1) && (Track->TrackElementAt(894, Train.LeadElement).TrackType == Continuation))
9721  {
9722  Train.SetTrainMovementValues(21, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
9723  }
9724  else if((Train.MidElement > -1) && (Track->TrackElementAt(895, Train.MidElement).TrackType == Continuation))
9725  {
9726  Train.SetTrainMovementValues(22, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
9727  }
9728  else if((Train.LagElement > -1) && (Track->TrackElementAt(896, Train.LagElement).TrackType == Continuation))
9729  {
9730  Train.SetTrainMovementValues(23, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
9731  }
9732  }
9733  else if(Train.StoppedAtSignal)
9734  {
9735  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9736  if(!Train.TrainFailed)
9737  {
9739  }
9740  // TrainController->LogActionError(42, Train.HeadCode, "", SignalHold, Track->TrackElementAt(757, NextElementPos).ElementID);
9741  }
9742  }
9743  Train.LogAction(1, Train.HeadCode, "", RestoreTimetableControl, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9744  Utilities->CallLogPop(1195);
9745  }
9746  catch(const Exception &e)
9747  {
9748  ErrorLog(158, e.Message);
9749  }
9750 }
9751 
9752 // ---------------------------------------------------------------------------
9753 
9754 void __fastcall TInterface::ChangeDirectionMenuItemClick(TObject *Sender)
9755 {
9756  try
9757  {
9758  TrainController->LogEvent("ChangeDirectionMenuItemClick");
9759  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ChangeDirectionMenuItemClick");
9761  Train.SignallerStoppingFlag = false;
9762  Train.SignallerChangeTrainDirection(0); // this unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd
9763  Train.SignallerStopped = true;
9764  AnsiString LocName = "";
9765  if(Train.LeadElement > -1)
9766  {
9767  LocName = Track->TrackElementAt(637, Train.LeadElement).ActiveTrackElementName;
9768  }
9769  if((LocName == "") && (Train.MidElement > -1))
9770  {
9771  LocName = Track->TrackElementAt(638, Train.MidElement).ActiveTrackElementName;
9772  }
9773  if((LocName == "") && Train.LeadElement > -1)
9774  {
9775  LocName = Track->TrackElementAt(639, Train.LeadElement).ElementID;
9776  }
9777  if((LocName == "") && (Train.MidElement > -1))
9778  {
9779  LocName = Track->TrackElementAt(640, Train.MidElement).ElementID;
9780  }
9781  Train.LogAction(2, Train.HeadCode, "", SignallerChangeDirection, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9782  Utilities->CallLogPop(1196);
9783  }
9784  catch(const Exception &e)
9785  {
9786  ErrorLog(159, e.Message);
9787  }
9788 }
9789 // ---------------------------------------------------------------------------
9790 
9791 void __fastcall TInterface::MoveForwardsMenuItemClick(TObject *Sender)
9792 {
9793  try
9794  {
9795  TrainController->LogEvent("MoveForwardsMenuItemClick");
9796  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MoveForwardsMenuItemClick");
9798  Train.SignallerStoppingFlag = false;
9799  if(!Train.AbleToMove(2))
9800  { // shouldn't be here as when unable to move MoveForwards shouldn't be enabled, but leave in as a precaution
9801  Utilities->CallLogPop(1197);
9802  return;
9803  }
9804  Train.SignallerStopped = false;
9805  Train.StoppedAfterSPAD = false; // in case had been set
9806  Train.SPADFlag = false;
9807  Train.StoppedAtLocation = false; // may not have been set but reset anyway
9808  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9810  Train.EntrySpeed = 0;
9812  Train.FirstHalfMove = true;
9813  int NextElementPos = -1; // addition for v1.3.2 due to Carwyn Thomas error
9814  int NextEntryPos = -1; // ---ditto---
9815  if(Train.LeadElement > -1) // ---ditto---
9816  { // ---ditto---
9817  NextElementPos = Track->TrackElementAt(652, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
9818  NextEntryPos = Track->TrackElementAt(657, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
9819  } // ---ditto---
9820  if((NextElementPos > -1) && (NextEntryPos > -1))
9821  {
9822  Train.SetTrainMovementValues(14, NextElementPos, NextEntryPos); // NextElement is the element to be entered
9823  }
9824  // else follow the continuations
9825  else if((Train.LeadElement > -1) && (Track->TrackElementAt(784, Train.LeadElement).TrackType == Continuation))
9826  {
9827  Train.SetTrainMovementValues(17, Train.LeadElement, Train.LeadEntryPos); // Use LeadElement for calcs if lead is a continuation
9828  }
9829  else if((Train.MidElement > -1) && (Track->TrackElementAt(785, Train.MidElement).TrackType == Continuation))
9830  {
9831  Train.SetTrainMovementValues(18, Train.MidElement, Train.MidEntryPos); // Use MidElement for calcs if Mid is a continuation
9832  }
9833  else if((Train.LagElement > -1) && (Track->TrackElementAt(786, Train.LagElement).TrackType == Continuation))
9834  {
9835  Train.SetTrainMovementValues(19, Train.LagElement, Train.LagEntryPos); // Use LagElement for calcs if Lag is a continuation
9836  }
9837  Train.LogAction(3, Train.HeadCode, "", SignallerMoveForwards, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
9838  Utilities->CallLogPop(1198);
9839  }
9840  catch(const Exception &e)
9841  {
9842  ErrorLog(160, e.Message);
9843  }
9844 }
9845 // ---------------------------------------------------------------------------
9846 
9847 void __fastcall TInterface::SignallerJoinedByMenuItemClick(TObject *Sender)
9848 { // new at v2.4.0
9849  try
9850  {
9851  TrainController->LogEvent("JoinedByMenuItemClick");
9852  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",JoinedByMenuItemClick");
9853  TTrain *TrainToBeJoinedBy;
9855  if(ThisTrain.IsThereAnAdjacentTrain(1, TrainToBeJoinedBy)) // this must come before both powers zero check in order to set a valid TrainToBeJoinedBy
9856  {
9857  if(TrainToBeJoinedBy->TrainMode != Signaller)
9858  {
9859  TrainController->StopTTClockMessage(91, "Adjacent train must be under signaller control in order to join");
9860  Utilities->CallLogPop(2156);
9861  return;
9862  }
9863  // here if there is an adjacent train under signaller control
9864  if((TrainToBeJoinedBy->PowerAtRail < 1) && (ThisTrain.PowerAtRail < 1))
9865  {
9866  ShowMessage("Can't join two trains when both are without power");
9867  Utilities->CallLogPop(2157);
9868  return;
9869  }
9870  AnsiString TrainToBeJoinedByHeadCode = TrainToBeJoinedBy->HeadCode;
9871  // set new values for mass etc
9872  double OtherBrakeForce = TrainToBeJoinedBy->MaxBrakeRate * TrainToBeJoinedBy->Mass;
9873  double OwnBrakeForce = ThisTrain.MaxBrakeRate * ThisTrain.Mass;
9874  double CombinedBrakeRate = (OtherBrakeForce + OwnBrakeForce) / (TrainToBeJoinedBy->Mass + ThisTrain.Mass);
9875  ThisTrain.Mass += TrainToBeJoinedBy->Mass;
9876  ThisTrain.MaxBrakeRate = CombinedBrakeRate;
9877  ThisTrain.PowerAtRail += TrainToBeJoinedBy->PowerAtRail;
9878  ThisTrain.AValue = sqrt(2 * ThisTrain.PowerAtRail / ThisTrain.Mass);
9879 
9880  TrainToBeJoinedBy->TrainGone = true; // this will cause other train to be deleted
9881  TrainToBeJoinedBy->JoinedOtherTrainFlag = true;
9882  AnsiString LocName = "";
9883  if(ThisTrain.LeadElement > -1)
9884  {
9885  LocName = Track->TrackElementAt(979, ThisTrain.LeadElement).ActiveTrackElementName;
9886  }
9887  if((LocName == "") && (ThisTrain.MidElement > -1))
9888  {
9889  LocName = Track->TrackElementAt(980, ThisTrain.MidElement).ActiveTrackElementName;
9890  }
9891  if((LocName == "") && ThisTrain.LeadElement > -1)
9892  {
9893  LocName = Track->TrackElementAt(981, ThisTrain.LeadElement).ElementID;
9894  }
9895  if((LocName == "") && (ThisTrain.MidElement > -1))
9896  {
9897  LocName = Track->TrackElementAt(982, ThisTrain.MidElement).ElementID;
9898  }
9899  ThisTrain.StoppedWithoutPower = true;
9900  if(ThisTrain.PowerAtRail >= 1)
9901  {
9902  ThisTrain.StoppedWithoutPower = false;
9903  }
9904  ThisTrain.TrainFailed = false; // if had failed then no longer failed, even if joining train has no power
9905  if(!ThisTrain.StoppedAtLocation)
9906  {
9907  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9909  }
9910  else
9911  {
9912  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9914  }
9915  ThisTrain.SignallerStopped = true; // maybe as well as stopped without power, thought that takes precedence in floating window
9916  ThisTrain.LogAction(34, ThisTrain.HeadCode, TrainToBeJoinedBy->HeadCode, SignallerJoin, LocName, TDateTime(0), false); // TDateTime isn't used
9917  ThisTrain.ZeroPowerNoFrontSplitMessage = false; // added at v2.4.0, no need to include TrainToBeJoinedBy as that will be removed
9918  ThisTrain.ZeroPowerNoRearSplitMessage = false;
9919  ThisTrain.FailedTrainNoFinishJoinMessage = false;
9920  ThisTrain.ZeroPowerNoJoinedByMessage = false;
9921  ThisTrain.ZeroPowerNoCDTMessage = false;
9922  ThisTrain.ZeroPowerNoNewServiceMessage = false;
9924  ThisTrain.ZeroPowerNoRepeatShuttleMessage = false;
9926  Utilities->CallLogPop(2158);
9927  }
9928  }
9929  catch(const Exception &e)
9930  {
9931  ErrorLog(207, e.Message);
9932  }
9933 }
9934 // ---------------------------------------------------------------------------
9935 
9936 void __fastcall TInterface::RepairFailedTrainMenuItemClick(TObject *Sender)
9937 { // added at v2.4.0
9938  try
9939  {
9940  TrainController->LogEvent("RepairFailedTrainMenuItemClick");
9941  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedTrainMenuItemClick");
9943  Train.TrainFailed = false;
9944  Train.StoppedWithoutPower = false;
9945  Train.SignallerStopped = true;
9946  if(!Train.StoppedAtLocation)
9947  {
9948  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9950  }
9951  else
9952  {
9953  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
9955  }
9956  Train.PowerAtRail = Train.OriginalPowerAtRail; // recover from original value, new at v2.4.0
9957  Train.AValue = sqrt(2 * Train.PowerAtRail / Train.Mass);
9958  Train.SetTrainMovementValues(24, Train.LeadElement, Train.LeadEntryPos);
9959  AnsiString LocName = "";
9960  if(Train.LeadElement > -1)
9961  {
9962  LocName = Track->TrackElementAt(983, Train.LeadElement).ActiveTrackElementName;
9963  }
9964  if((LocName == "") && (Train.MidElement > -1))
9965  {
9966  LocName = Track->TrackElementAt(984, Train.MidElement).ActiveTrackElementName;
9967  }
9968  if((LocName == "") && Train.LeadElement > -1)
9969  {
9970  LocName = Track->TrackElementAt(985, Train.LeadElement).ElementID;
9971  }
9972  if((LocName == "") && (Train.MidElement > -1))
9973  {
9974  LocName = Track->TrackElementAt(986, Train.MidElement).ElementID;
9975  }
9976  Train.LogAction(35, Train.HeadCode, "", RepairFailedTrain, LocName, TrainController->TTClockTime, false); // false for no warning
9977  Train.ZeroPowerNoFrontSplitMessage = false;
9978  Train.ZeroPowerNoRearSplitMessage = false;
9979  Train.FailedTrainNoFinishJoinMessage = false;
9980  Train.ZeroPowerNoJoinedByMessage = false;
9981  Train.ZeroPowerNoCDTMessage = false;
9982  Train.ZeroPowerNoNewServiceMessage = false;
9984  Train.ZeroPowerNoRepeatShuttleMessage = false;
9986  Utilities->CallLogPop(2159);
9987  }
9988  catch(const Exception &e)
9989  {
9990  ErrorLog(208, e.Message);
9991  }
9992 }
9993 
9994 // ---------------------------------------------------------------------------
9995 
9996 void __fastcall TInterface::SignallerControlStopMenuItemClick(TObject *Sender)
9997 {
9998  try
9999  {
10000  TrainController->LogEvent("SignallerControlStopMenuItemClick");
10001  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SignallerControlStopMenuItemClick");
10004  if(Train.LeadElement > -1)
10005  {
10006  if(Track->TrackElementAt(787, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
10007  {
10008  Train.SignallerStoppingFlag = true;
10009  Train.SignallerStopBrakeRate = 0;
10010  Train.LogAction(24, Train.HeadCode, "", SignallerControlStop, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10011  }
10012  else
10014  }
10015  else
10017  Utilities->CallLogPop(1553);
10018  }
10019  catch(const Exception &e)
10020  {
10021  ErrorLog(161, e.Message);
10022  }
10023 }
10024 
10025 // ---------------------------------------------------------------------------
10026 void __fastcall TInterface::PassRedSignalMenuItemClick(TObject *Sender)
10027 {
10028  try
10029  {
10030  TrainController->LogEvent("PassRedSignalMenuItemClick");
10031  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PassRedSignalMenuItemClick");
10033  Train.SignallerStoppingFlag = false;
10034  int NextElementPos = Track->TrackElementAt(712, Train.LeadElement).Conn[Train.LeadExitPos];
10035  if(NextElementPos < 0)
10036  {
10037  throw Exception("Error, no element in front in PassRedSignalMenuItemClick");
10038  }
10039  TTrackElement &TrackElement = Track->TrackElementAt(653, NextElementPos);
10040 /* drop this error as may be some circumstances where behind a signal in sig mode but not stopped at signal
10041  if(!Train.StoppedAtSignal)
10042  {
10043  throw Exception("Error, not StoppedAtSignal in PassRedSignalMenuItemClick");
10044  }
10045 */
10046  if(TrackElement.TrackType != SignalPost)
10047  {
10048  throw Exception("Error, next element not a signal type in PassRedSignalMenuItemClick");
10049  }
10050  Train.SignallerStopped = false;
10051  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
10052  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
10053  // since no need to alert the user
10054  Train.StoppedAfterSPAD = false; // in case had been set
10055  Train.SPADFlag = false;
10056  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10058  Train.AllowedToPassRedSignal = true;
10059  Train.LogAction(4, Train.HeadCode, "", SignallerPassRedSignal, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10060  Utilities->CallLogPop(1199);
10061  }
10062  catch(const Exception &e)
10063  {
10064  ErrorLog(162, e.Message);
10065  }
10066 }
10067 // ---------------------------------------------------------------------------
10068 
10069 void __fastcall TInterface::StepForwardMenuItemClick(TObject *Sender)
10070 {
10071  try
10072  {
10073  TrainController->LogEvent("StepForwardMenuItemClick");
10074  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",StepForwardMenuItemClick");
10076  Train.SignallerStoppingFlag = false;
10077  Train.SignallerStopped = false;
10078  Train.StoppedAtLocation = false; // may have started at station in signaller mode and also at a red signal, in this case both SignallerStopped
10079  // and StoppedAtLocation are set but the background colour stays pale green for station, not signal,
10080  // since no need to alert the user
10081  Train.StoppedAfterSPAD = false; // in case had been set
10082  Train.SPADFlag = false;
10083  Train.StepForwardFlag = true;
10084  Train.AllowedToPassRedSignal = true; // in case at a signal, will clear when half-way into next element whether a signal or not
10085  // ok to call PlotTrainWithNewBackgroundColour here as PlotElements already set to Lead, Mid & Lag elements
10087  Train.LogAction(32, Train.HeadCode, "", SignallerStepForward, "", TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10088  int NextElementPos = -1;
10089 // addition for v1.3.2 due to Carwyn Thomas error: can't select StepForwardMenuItem if exiting at a continuation but leave this in anyway
10090  int NextEntryPos = -1; // ---ditto---
10091  if(Train.LeadElement > -1) // ---ditto---
10092  { // ---ditto---
10093  NextElementPos = Track->TrackElementAt(804, Train.LeadElement).Conn[Train.LeadExitPos]; // had 'int' prefix before additions
10094  NextEntryPos = Track->TrackElementAt(805, Train.LeadElement).ConnLinkPos[Train.LeadExitPos]; // ---ditto---
10095  } // ---ditto---
10096  if((NextElementPos > -1) && (NextEntryPos > -1))
10097  { // call this after StepForwardFlag set
10098  Train.EntrySpeed = 0;
10100  Train.FirstHalfMove = true;
10101  Train.SetTrainMovementValues(20, NextElementPos, NextEntryPos); // NextElement is the element to be entered
10102  }
10103  Utilities->CallLogPop(1800);
10104  }
10105  catch(const Exception &e)
10106  {
10107  ErrorLog(163, e.Message);
10108  }
10109 }
10110 
10111 // ---------------------------------------------------------------------------
10112 
10113 void __fastcall TInterface::RemoveTrainMenuItemClick(TObject *Sender)
10114 {
10115  try
10116  {
10117  TrainController->LogEvent("RemoveTrainMenuItemClick");
10118  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RemoveTrainMenuItemClick");
10120  if((!Train.Derailed) && (!Train.Crashed))
10121  {
10122  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
10124  UnicodeString Message = UnicodeString(Train.HeadCode) + " will be removed from the railway - proceed?";
10125  int button = Application->MessageBox(Message.c_str(), L"Please confirm", MB_YESNO);
10126  TrainController->BaseTime = TDateTime::CurrentDateTime();
10128  if(button == IDNO)
10129  {
10130  Utilities->CallLogPop(1801);
10131  return;
10132  }
10133  }
10134  Train.SignallerStoppingFlag = false;
10135  Train.TrainGone = true; // will be removed by TTrainController::Operate
10136  Train.SignallerRemoved = true;
10137  Train.TrainDataEntryPtr->TrainOperatingDataVector.at(Train.RepeatNumber).RunningEntry = Exited;
10138  AnsiString LocName = "";
10139  if(Train.LeadElement > -1)
10140  {
10141  LocName = Track->TrackElementAt(641, Train.LeadElement).ActiveTrackElementName;
10142  }
10143  if((LocName == "") && (Train.MidElement > -1))
10144  {
10145  LocName = Track->TrackElementAt(642, Train.MidElement).ActiveTrackElementName;
10146  }
10147  if((LocName == "") && Train.LeadElement > -1)
10148  {
10149  LocName = Track->TrackElementAt(643, Train.LeadElement).ElementID;
10150  }
10151  if((LocName == "") && (Train.MidElement > -1))
10152  {
10153  LocName = Track->TrackElementAt(644, Train.MidElement).ElementID;
10154  }
10155  TTrackElement *TrackElementPtr;
10156  int RouteNumber;
10157  TAllRoutes::TRouteType RouteType;
10158  if(Train.LeadElement > -1)
10159  {
10160  TrackElementPtr = &(Track->TrackElementAt(673, Train.LeadElement));
10161  // remove TrainIDs from track element, added at v2.4.0
10162  if(TrackElementPtr->TrackType == Bridge)
10163  {
10164  if(Train.LeadExitPos > 1)
10165  {
10166  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
10167  }
10168  else
10169  {
10170  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
10171  }
10172  }
10173  else
10174  {
10175  TrackElementPtr->TrainIDOnElement = -1;
10176  }
10177  // reset any CallingOnSet flags for signals, if facing wrong way doesn't matter, shouldn't be set anyay
10178  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10179  {
10180  TrackElementPtr->CallingOnSet = false;
10181  Track->PlotSignal(6, *TrackElementPtr, Display);
10182  }
10183 // [added at v1.3.0] here check if on an automatic signals route and if so reset signals for the entire route from the
10184 // start of the route - after the train has been removed, use LeadElement and also MidElement (if no autosigs route at LeadElement) just to be sure
10185  RouteType = AllRoutes->GetRouteTypeAndNumber(27, Train.LeadElement, Train.LeadEntryPos, RouteNumber);
10186  if(RouteType == TAllRoutes::AutoSigsRoute)
10187  {
10190  }
10191 // end of addition
10192  }
10193  if(Train.MidElement > -1)
10194  {
10195  TrackElementPtr = &(Track->TrackElementAt(674, Train.MidElement));
10196  // remove TrainIDs from track element, added at v2.4.0
10197  if(TrackElementPtr->TrackType == Bridge)
10198  {
10199  if(Train.MidExitPos > 1)
10200  {
10201  TrackElementPtr->TrainIDOnBridgeTrackPos23 = -1;
10202  }
10203  else
10204  {
10205  TrackElementPtr->TrainIDOnBridgeTrackPos01 = -1;
10206  }
10207  }
10208  else
10209  {
10210  TrackElementPtr->TrainIDOnElement = -1;
10211  }
10212  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10213  {
10214  TrackElementPtr->CallingOnSet = false;
10215  Track->PlotSignal(7, *TrackElementPtr, Display);
10216  }
10217 // [added at v1.3.0 as above]
10219  {
10220  RouteType = AllRoutes->GetRouteTypeAndNumber(28, Train.MidElement, Train.MidEntryPos, RouteNumber);
10221  if(RouteType == TAllRoutes::AutoSigsRoute)
10222  {
10225  }
10226  }
10227 // end of addition
10228  }
10229  if(Train.LeadElement > -1)
10230  // addition for v1.3.2 after Carwyn Thomas fault reported 24/05/15 - need to check if exiting at continuation (LeadElement == -1) as if so fails at next line
10231  {
10232  if(Track->TrackElementAt(675, Train.LeadElement).Conn[Train.LeadExitPos] > -1)
10233  {
10234  TrackElementPtr = &(Track->TrackElementAt(676, Track->TrackElementAt(677, Train.LeadElement).Conn[Train.LeadExitPos]));
10235  if((TrackElementPtr->TrackType == SignalPost) && TrackElementPtr->CallingOnSet)
10236  {
10237  TrackElementPtr->CallingOnSet = false;
10238  Track->PlotSignal(8, *TrackElementPtr, Display);
10239  }
10240  }
10241  }
10242  Train.LogAction(5, Train.HeadCode, "", RemoveTrain, LocName, TDateTime(0), false); // TDateTime is a dummy entry, false for no warning
10243  if(Train.ActionVectorEntryPtr->Command != "Frh") // if remaining at location no point in sending 'failed to terminate' message
10244  {
10245  Train.SendMissedActionLogs(0, -1, Train.ActionVectorEntryPtr); // -1 is a marker for send messages for all remaining
10246  } // entries, including Fer if present
10247  Utilities->CallLogPop(1200);
10248  }
10249  catch(const Exception &e)
10250  {
10251  ErrorLog(164, e.Message);
10252  }
10253 }
10254 
10255 // ---------------------------------------------------------------------------
10256 
10257 void __fastcall TInterface::ErrorButtonClick(TObject *Sender)
10258  // to terminate after error message given
10259 {
10260  ErrorMessage->Visible = false;
10261  ErrorMessageStoreImage->Visible = false;
10262  ErrorButton->Visible = false;
10263  Display->GetImage()->Visible = true;
10264  Application->Terminate();
10265 }
10266 
10267 // ---------------------------------------------------------------------------
10268 void __fastcall TInterface::PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
10269 {
10270  try
10271  {
10272  TrainController->LogEvent("PerformancePanelLabelStartDrag");
10273  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PerformancePanelLabelStartDrag");
10274  PerformancePanelDragStartX = Mouse->CursorPos.x - PerformancePanel->Left;
10275  PerformancePanelDragStartY = Mouse->CursorPos.y - PerformancePanel->Top;
10276  Utilities->CallLogPop(1202);
10277  }
10278  catch(const Exception &e)
10279  {
10280  ErrorLog(165, e.Message);
10281  }
10282 }
10283 // ---------------------------------------------------------------------------
10284 
10285 void __fastcall TInterface::FormClose(TObject *Sender, TCloseAction &Action)
10286 {
10287  try
10288  {
10289  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",FormClose");
10291  {
10292  UnicodeString MessageStr =
10293  "Note that leaving the track unlinked will cause preferred directions to be lost on reloading. Prevent by linking the track then resaving. Do you still wish to exit?";
10294  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
10295  if(button == IDNO)
10296  {
10297  Action = caNone; // prevents form & application from closing
10298  Utilities->CallLogPop(1712);
10299  return;
10300  }
10301  }
10303  {
10304  UnicodeString MessStr = "";
10306  {
10307  MessStr = UnicodeString("The railway and the timetable have both changed, exit without saving either?");
10308  }
10309  else if(FileChangedFlag)
10310  {
10311  MessStr = UnicodeString("The railway has changed, exit without saving?");
10312  }
10313  else
10314  {
10315  MessStr = UnicodeString("The timetable has changed, exit without saving?");
10316  }
10317  int button = Application->MessageBox(MessStr.c_str(), L"Please confirm", MB_YESNO);
10318  if(button == IDNO)
10319  {
10320  Action = caNone; // prevents form & application from closing
10321  Utilities->CallLogPop(1133);
10322  return;
10323  }
10324  }
10325 
10326  if(Level1Mode == OperMode)
10327  {
10328  UnicodeString MessageStr = "Please note that the session will be lost if it hasn't been saved. Do you still wish to exit?";
10329  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
10331  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
10332  TrainController->BaseTime = TDateTime::CurrentDateTime();
10334  if(button == IDNO)
10335  {
10336  Action = caNone; // prevents form & application from closing
10337  Utilities->CallLogPop(969);
10338  return;
10339  }
10341  Utilities->PerformanceFile.close();
10342  }
10343  if((TempTTFileName != "") && FileExists(TempTTFileName))
10344  {
10345  DeleteFile(TempTTFileName);
10346  }
10347  Utilities->CallLogPop(971);
10348  }
10349  catch(const Exception &e)
10350  {
10351  ErrorLog(166, e.Message);
10352  }
10353 }
10354 
10355 // ---------------------------------------------------------------------------
10356 
10357 void __fastcall TInterface::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
10358 {
10359 // TrainController->LogEvent("FormKeyDown," + AnsiString(Key));
10360 // drop event log as have too many spurious entries
10361  try
10362  {
10363  if((Shift.Contains(ssAlt)) && (Shift.Contains(ssCtrl)))
10364  {
10365  if(Key == '2')
10366  {
10367  if(CallLogTickerLabel->Visible)
10368  {
10369  CallLogTickerLabel->Visible = false;
10370  }
10371  else
10372  {
10373  CallLogTickerLabel->Visible = true;
10374  }
10375  }
10376  else if(Key == '3')
10377  {
10378  if(DevelopmentPanel->Visible)
10379  {
10380  DevelopmentPanel->Visible = false;
10381  }
10382  else
10383  {
10384  DevelopmentPanel->Visible = true;
10385  DevelopmentPanel->BringToFront();
10386  }
10387  }
10388  else if(Key == '4')
10389  {
10390  TestFunction();
10391  }
10392  }
10393  else if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10394  {
10395  CtrlKey = true;
10396  }
10397  else if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
10398  {
10399  ShiftKey = true;
10400  }
10401 
10402 // below added at v1.3.0 to allow keyboard scrolling as well as mouse button scrolling - see user suggestion on Features & Requests forum 30/09/12
10403 // the NonCTRLOrSHIFTKeyUpFlag prevents repeated viewpoint movements without keys being re-pressed
10404 // note that use the OnKeyDown event rather than OnKeyPress as suggested by the user so that the CTRL & SHIFT keys can be taken into account
10405 
10406 //at v2.4.2 the flag changed to LastNonCtrlOrShiftKeyDown to make condition specific to last key, because when a message given the key up event
10407 //is not seen as the form does not have focus, so with the flag no shortcut key will work on the first press, with this only the same shortcut key
10408 //won't work on first press and that is less likely to be used a second time on either side of the message
10409 
10410  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
10411  {
10412  if(LastNonCtrlOrShiftKeyDown == Key) //same key still down rejected
10413  {
10414  return;
10415  }
10416  else
10417  {
10419  }
10420  }
10421 
10422  if(Key == VK_UP)
10423  {
10424  if(ScreenUpButton->Enabled)
10425  ScreenUpButton->Click();
10426  }
10427  else if(Key == VK_DOWN)
10428  {
10429  if(ScreenDownButton->Enabled)
10430  ScreenDownButton->Click();
10431  }
10432  else if(Key == VK_LEFT)
10433  {
10434  if(ScreenLeftButton->Enabled)
10435  ScreenLeftButton->Click();
10436  }
10437  else if(Key == VK_RIGHT)
10438  {
10439  if(ScreenRightButton->Enabled)
10440  ScreenRightButton->Click();
10441  }
10442  else if(Key == VK_HOME)
10443  {
10444  if(HomeButton->Enabled)
10445  HomeButton->Click();
10446  }
10447 // end of 1.3.0 addition
10448  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
10449  {
10450  if(ZoomButton->Enabled)
10451  ZoomButton->Click();
10452  }
10453  else if(Key == VK_END) // added at v2.2.0 to toggle zoom using 'End' key
10454  {
10455  if(ZoomButton->Enabled)
10456  ZoomButton->Click();
10457  }
10458 
10459 //below added for v2.4.2 to add more keyboard shortcuts
10460  if(DistanceBox->Focused() || SpeedLimitBox->Focused() || MileEdit->Focused() || ChainEdit->Focused() || YardEdit->Focused() || SpeedEditBox2->Focused()
10461  || MTBFEditBox->Focused() || LocationNameTextBox->Focused() || TextBox->Focused() || PowerEditBox->Focused() || SpeedEditBox->Focused()
10462  || AddSubMinsBox->Focused() || OneEntryTimetableMemo->Focused())
10463  {// prevent letter keys interfering when these boxes have focus - many are mutually exclusive but include them all
10464  return;
10465  }
10466 
10467  if(Shift.Contains(ssShift) && !Shift.Contains(ssAlt) && !Shift.Contains(ssCtrl) && NewHomeButton->Enabled && NewHomeButton->Visible)
10468  {
10469  if(Level1Mode != TimetableMode && (Key == 'H' || Key == 'h'))//TimetablePanel uses Shift H too so disable this when it's in use
10470  {
10471  NewHomeButton->Click();
10472  }
10473  }
10474 
10475 //Operating panel
10476  if(Level1Mode == OperMode && OperatingPanel->Enabled && OperatingPanel->Visible && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10477  { //use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
10478  if(!Shift.Contains(ssCtrl))
10479  {
10480  if(OperateButton->Visible && OperateButton->Enabled)
10481  {
10482  if(Level2OperMode == Operating && (Key == 'P' || Key == 'p'))
10483  {
10484  OperateButton->Click();
10485  }
10486  else if((Level2OperMode == Paused || Level2OperMode == PreStart) && (Key == 'R' || Key == 'r'))
10487  {
10488  OperateButton->Click();
10489  }
10490  }
10491  if(PresetAutoSigRoutesButton->Visible && PresetAutoSigRoutesButton->Enabled && (Key == 'A' || Key == 'a'))
10492  {
10493  PresetAutoSigRoutesButton->Click();
10494  }
10495  if(PerformanceLogButton->Visible && PerformanceLogButton->Enabled && (Key == 'L' || Key == 'l'))
10496  {
10497  PerformanceLogButton->Click();
10498  }
10499  if(CallingOnButton->Visible && CallingOnButton->Enabled && (Key == 'O' || Key == 'o'))
10500  {
10501  CallingOnButton->Click();
10502  }
10503  if(OperatorActionButton->Visible && OperatorActionButton->Enabled && (Key == 'D' || Key == 'd'))
10504  {
10505  OperatorActionButton->Click();
10506  }
10507  if(RouteCancelButton->Visible && RouteCancelButton->Enabled && (Key == 'C' || Key == 'c'))
10508  {
10509  RouteCancelButton->Click();
10510  }
10511  if(TTClockAdjButton->Visible && TTClockAdjButton->Enabled && (Key == 'T' || Key == 't'))
10512  {
10513  TTClockAdjButton->Click();
10514  }
10515  if(AutoSigsButton->Visible && AutoSigsButton->Enabled && Key == '1') //route buttons - autosigs
10516  {
10517  AutoSigsButton->Click();
10518  }
10519  if(SigPrefButton->Visible && SigPrefButton->Enabled && Key == '2') //route buttons - prefdir
10520  {
10521  SigPrefButton->Click();
10522  }
10523  if(UnrestrictedButton->Visible && UnrestrictedButton->Enabled && Key == '3') //route buttons - unrestricted
10524  {
10525  UnrestrictedButton->Click();
10526  }
10527  if(ExitOperationButton->Visible && ExitOperationButton->Enabled && Key == '\x1b')
10528  {
10529  ExitOperationButton->Click();
10530  }
10531  }
10532  else //CtrlKey down
10533  {
10534  if(SaveSessionButton->Visible && SaveSessionButton->Enabled)
10535  {
10536  SaveMenuItem->ShortCut = 0; //It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
10537  if(Key == 'S' || Key == 's')//so this will never execute
10538  {
10539  SaveSessionButton->Click();
10540  }
10541  }
10542  }
10543  }
10544 
10545 //Timetable clock adjust panel
10546  if(Level1Mode == OperMode && TTClockAdjPanel->Enabled && TTClockAdjPanel->Visible && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
10547  { //use Shift.Contains(ssShift etc instead of ShiftKey as that not set if pressed second after Ctrl key pressed
10548  if(Shift.Contains(ssShift))
10549  {
10550  if(TTClockExitButton->Visible && TTClockExitButton->Enabled && (Key == 'A' || Key == 'a'))
10551  {
10552  TTClockExitButton->Click();
10553  }
10554  if(TTClockResetButton->Visible && TTClockResetButton->Enabled && (Key == 'R' || Key == 'r'))
10555  {
10556  TTClockResetButton->Click();
10557  }
10558  }
10559  }
10560 
10561 //Track build panel
10562  if((Level1Mode == TrackMode) && TrackBuildPanel->Visible && TrackBuildPanel->Enabled)
10563  {
10564  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl) && !Shift.Contains(ssAlt))
10565  {
10566  if(AddTrackButton->Visible && AddTrackButton->Enabled && (Key == 'A' || Key == 'a')) //add/remove track elements
10567  {
10568  AddTrackButton->Click();
10569  }
10570  if(SigAspectButton->Visible && SigAspectButton->Enabled && (Key == 'S' || Key == 's')) //cycle through signal aspects
10571  {
10572  SigAspectButton->Click();
10573  }
10574  if(TrackOKButton->Visible && TrackOKButton->Enabled && (Key == 'L' || Key == 'l')) //link track
10575  {
10576  TrackOKButton->Click();
10577  }
10578  if(FontButton->Visible && FontButton->Enabled && (Key == 'F' || Key == 'f')) //change font
10579  {
10580  FontButton->Click();
10581  }
10582  if(LocationNameButton->Visible && LocationNameButton->Enabled && (Key == 'N' || Key == 'n')) //name locations
10583  {
10584  LocationNameButton->Click();
10585  }
10586  if(SetLengthsButton->Visible && SetLengthsButton->Enabled && (Key == 'D' || Key == 'd')) //set distances/speeds
10587  {
10588  SetLengthsButton->Click();
10589  }
10590  if(AddTextButton->Visible && AddTextButton->Enabled && (Key == 'T' || Key == 't')) //add text
10591  {
10592  AddTextButton->Click();
10593  }
10594  if(ScreenGridButton->Visible && ScreenGridButton->Enabled && (Key == 'G' || Key == 'g')) //toggle grid
10595  {
10596  ScreenGridButton->Click();
10597  }
10598  if(MoveTextOrGraphicButton->Visible && MoveTextOrGraphicButton->Enabled && (Key == 'M' || Key == 'm')) //move text or graphic
10599  {
10600  MoveTextOrGraphicButton->Click();
10601  }
10602  if(UserGraphicButton->Visible && UserGraphicButton->Enabled && (Key == 'I' || Key == 'i')) //insert image
10603  {
10604  UserGraphicButton->Click();
10605  }
10606  if(SetGapsButton->Visible && SetGapsButton->Enabled && (Key == 'J' || Key == 'j')) //join gaps
10607  {
10608  SetGapsButton->Click();
10609  }
10610  }
10611  if(Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10612  {
10613  if(SaveRailwayTBPButton->Visible && SaveRailwayTBPButton->Enabled) //save railway in trackbuild mode
10614  {
10615  SaveMenuItem->ShortCut = 0; //It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
10616  if(Key == 'S' || Key == 's')//so this will never execute
10617  {
10618  SaveRailwayTBPButton->Click();
10619  }
10620  }
10621  }
10622  if(!Shift.Contains(ssCtrl) && !Shift.Contains(ssShift) && !Shift.Contains(ssAlt))
10623  {
10624  if((ExitTrackButton->Visible && ExitTrackButton->Enabled) && Key == '\x1b') //escape key
10625  {
10626  ExitTrackButton->Click();
10627  }
10628  }
10629  }
10630 
10631 //PrefDir panel
10632  if(Level1Mode == PrefDirMode && PrefDirPanel->Visible && PrefDirPanel->Enabled && !Shift.Contains(ssAlt))
10633  {
10634  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10635  {
10636  if((ExitPrefDirButton->Visible && ExitPrefDirButton->Enabled) && Key == '\x1b') //escape key
10637  {
10638  ExitPrefDirButton->Click();
10639  }
10640  }
10641  if(!Shift.Contains(ssShift) && Shift.Contains(ssCtrl))
10642  {
10643  if(SaveRailwayPDPButton->Visible && SaveRailwayPDPButton->Enabled)
10644  {
10645  SaveMenuItem->ShortCut = 0; //It's normally 16467 (Ctrl S) & will be restored in FormKeyUp. Has to be reset or will grab the key combination
10646  if(Key == 'S' || Key == 's')//so this will never execute
10647  {
10648  SaveRailwayPDPButton->Click();
10649  }
10650  }
10651  }
10652  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10653  {
10654  if(AddPrefDirButton->Visible && AddPrefDirButton->Enabled && (Key == 'A' || Key == 'a')) //add pref dir
10655  {
10656  AddPrefDirButton->Click();
10657  }
10658  if(DeleteOnePrefDirButton->Visible && DeleteOnePrefDirButton->Enabled && (Key == 'D' || Key == 'd')) //delete one pref dir
10659  {
10660  DeleteOnePrefDirButton->Click();
10661  }
10662  if(DeleteAllPrefDirButton->Visible && DeleteAllPrefDirButton->Enabled && (Key == 'C' || Key == 'c')) //delete all pref dirs
10663  {
10664  DeleteAllPrefDirButton->Click();
10665  }
10666  }
10667  }
10668 //Note that save button in BaseMode is handled by Ctrl S from the File menu
10669 
10670 //Timetable panel
10671  if(Level1Mode == TimetableMode && TimetablePanel->Visible && TimetablePanel->Enabled && !Shift.Contains(ssAlt))
10672  {
10673  if(!Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10674  {
10675  if(ExitTTModeButton->Visible && ExitTTModeButton->Enabled && Key == '\x1b') //escape key
10676  {
10677  ExitTTModeButton->Click();
10678  }
10679  }
10680  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl)) //show/hide timetable edit panel
10681  {
10682  if(ShowHideTTButton->Visible && ShowHideTTButton->Enabled)
10683  {
10684  if(!TimetableEditPanel->Visible)
10685  {
10686  if(Key == 'S' || Key == 's')
10687  {
10688  ShowHideTTButton->Click();
10689  }
10690  }
10691  else if(Key == 'H' || Key == 'h')
10692  {
10693  ShowHideTTButton->Click();
10694  }
10695  }
10696  }
10697  }
10698 
10699 //Timetable edit panel
10700 //These just set flags. The corresponding 'Click()' function executes separately to the keypress because Windows stores the key until after any directly linked key code
10701 //is executed then selects the timetable entry that begins with the letter corresponding to the key. Without this separation the list box is left with the wrong entry
10702 //showing. See DevHistory.txt for the version after v2.4.3 for details.
10703  if(Level1Mode == TimetableMode && TimetableEditPanel->Visible && TimetableEditPanel->Enabled && !Shift.Contains(ssAlt))
10704  {
10705  if(Shift.Contains(ssShift) && !Shift.Contains(ssCtrl))
10706  {
10707  AllEntriesTTListBoxTopPosition = AllEntriesTTListBox->TopIndex; //store value here before the Windows key press function runs (it runs after any local code)
10708  if(PreviousTTEntryButton->Enabled && (Key == 'L' || Key == 'l'))
10709  {
10710  PreviousTTEntryKeyFlag = true;
10711  }
10712  if(NextTTEntryButton->Enabled && (Key == 'N' || Key == 'n'))
10713  {
10714  NextTTEntryKeyFlag = true;
10715  }
10716  if(MoveTTEntryUpButton->Enabled && (Key == 'U' || Key == 'u'))
10717  {
10718  MoveTTEntryUpKeyFlag = true;
10719  }
10720  if(MoveTTEntryDownButton->Enabled && (Key == 'D' || Key == 'd'))
10721  {
10722  MoveTTEntryDownKeyFlag = true;
10723  }
10724  if(CopyTTEntryButton->Enabled && (Key == 'C' || Key == 'c'))
10725  {
10726  CopyTTEntryKeyFlag = true;
10727  }
10728  if(CutTTEntryButton->Enabled && (Key == 'X' || Key == 'x'))
10729  {
10730  CutTTEntryKeyFlag = true;
10731  }
10732  if(PasteTTEntryButton->Enabled && (Key == 'P' || Key == 'p'))
10733  {
10734  PasteTTEntryKeyFlag = true;
10735  }
10736  if(DeleteTTEntryButton->Enabled && (Key == 'E' || Key == 'e'))
10737  {
10738  DeleteTTEntryKeyFlag = true;
10739  }
10740 /* if(SaveTTEntryButton->Enabled && (Key == 'E' || Key == 'e')) //can't have save while editing entry as adds the letter to the entry
10741  {
10742  SaveTTEntryKeyFlag = true;
10743  }
10744  if(CancelTTActionButton->Enabled && (Key == 'K' || Key == 'k')) //can't have cancel while editing entry as adds the letter to the entry
10745  {
10746  CancelTTActionKeyFlag = true;
10747  }
10748 */
10749  if(NewTTEntryButton->Enabled && (Key == 'I' || Key == 'i'))
10750  {
10751  NewTTEntryKeyFlag = true;
10752  }
10753  if(AZOrderButton->Enabled && (Key == 'Z' || Key == 'z'))
10754  {
10755  AZOrderKeyFlag = true;
10756  }
10757 /*
10758  if(AddMinsButton->Enabled && (Key == 'M' || Key == 'm')) //can't have key here as adds the letter to the entry
10759  {
10760  AddMinsKeyFlag = true;
10761  }
10762  if(SubMinsButton->Enabled && (Key == 'B' || Key == 'b')) //can't have key here as adds the letter to the entry
10763  {
10764  SubMinsKeyFlag = true;
10765  }
10766 */
10767  if(TTServiceSyntaxCheckButton->Enabled && (Key == 'Q' || Key == 'q'))
10768  {
10770  }
10771  if(ValidateTimetableButton->Enabled && (Key == 'V' || Key == 'v'))
10772  {
10773  ValidateTimetableKeyFlag = true;
10774  }
10775  if(SaveTTButton->Enabled && (Key == 'T' || Key == 't'))
10776  {
10777  SaveTTKeyFlag = true;
10778  }
10779  if(SaveTTAsButton->Enabled && (Key == 'A' || Key == 'a'))
10780  {
10781  SaveTTAsKeyFlag = true;
10782  }
10783  if(RestoreTTButton->Enabled && (Key == 'R' || Key == 'r'))
10784  {
10785  RestoreTTKeyFlag = true;
10786  }
10787  if(ExportTTButton->Enabled && (Key == 'O' || Key == 'o'))
10788  {
10789  ExportTTKeyFlag = true;
10790  }
10791  if(ConflictAnalysisButton->Enabled && (Key == 'F' || Key == 'f'))
10792  {
10793  ConflictAnalysisKeyFlag = true;
10794  }
10795  }
10796  }
10797 
10798 
10799 //Information menu
10800  if(FloatingInfoMenu->Enabled && !Shift.Contains(ssAlt) && Shift.Contains(ssCtrl) && Shift.Contains(ssShift))
10801  {
10802  if(Key == 'I' || Key == 'i') //toggle track info
10803  {
10804  TrackInfoOnOffMenuItem->Click();
10805  }
10806  else if(TrainInfoMenuItem->Enabled)
10807  {
10808  if(Key == 'S' || Key == 's') //toggle train status info
10809  {
10811  }
10812  else if(Key == 'T' || Key == 't') //toggle train timetable info
10813  {
10814  TrainTTInfoOnOffMenuItem->Click();
10815  }
10816 
10817  }
10818  }
10819 //end of 2.4.2 addition
10820 
10821  }
10822  catch(const Exception &e)
10823  {
10824  ErrorLog(167, e.Message);
10825  }
10826 }
10827 
10828 // ---------------------------------------------------------------------------
10829 
10830 void __fastcall TInterface::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
10831 {
10832  if((Key != VK_SHIFT) && (Key != VK_CONTROL))
10833  LastNonCtrlOrShiftKeyDown = -1; //reset value to no key down
10834  CtrlKey = false;
10835  ShiftKey = false;
10836  SaveMenuItem->ShortCut = 16467; //restore Ctrl S for save menu in case set to 0 in FormKeyDown
10837 }
10838 
10839 // ---------------------------------------------------------------------------
10840 
10841 void __fastcall TInterface::OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10842 {
10843  if((Button == mbRight) && Level2OperMode == Operating)
10844  {
10845  OutputLog1->Caption = "";
10846  }
10847 }
10848 
10849 // ---------------------------------------------------------------------------
10850 
10851 void __fastcall TInterface::OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10852 {
10853  if((Button == mbRight) && Level2OperMode == Operating)
10854  {
10855  OutputLog2->Caption = "";
10856  }
10857 }
10858 // ---------------------------------------------------------------------------
10859 
10860 void __fastcall TInterface::OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10861 {
10862  if((Button == mbRight) && Level2OperMode == Operating)
10863  {
10864  OutputLog3->Caption = "";
10865  }
10866 }
10867 
10868 // ---------------------------------------------------------------------------
10869 
10870 void __fastcall TInterface::OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10871 {
10872  if((Button == mbRight) && Level2OperMode == Operating)
10873  {
10874  OutputLog4->Caption = "";
10875  }
10876 }
10877 
10878 // ---------------------------------------------------------------------------
10879 
10880 void __fastcall TInterface::OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10881 {
10882  if((Button == mbRight) && Level2OperMode == Operating)
10883  {
10884  OutputLog5->Caption = "";
10885  }
10886 }
10887 // ---------------------------------------------------------------------------
10888 
10889 void __fastcall TInterface::OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10890 {
10891  if((Button == mbRight) && Level2OperMode == Operating)
10892  {
10893  OutputLog6->Caption = "";
10894  }
10895 }
10896 
10897 // ---------------------------------------------------------------------------
10898 
10899 void __fastcall TInterface::OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10900 {
10901  if((Button == mbRight) && Level2OperMode == Operating)
10902  {
10903  OutputLog7->Caption = "";
10904  }
10905 }
10906 
10907 // ---------------------------------------------------------------------------
10908 
10909 void __fastcall TInterface::OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10910 {
10911  if((Button == mbRight) && Level2OperMode == Operating)
10912  {
10913  OutputLog8->Caption = "";
10914  }
10915 }
10916 
10917 // ---------------------------------------------------------------------------
10918 
10919 void __fastcall TInterface::OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10920 {
10921  if((Button == mbRight) && Level2OperMode == Operating)
10922  {
10923  OutputLog9->Caption = "";
10924  }
10925 }
10926 
10927 // ---------------------------------------------------------------------------
10928 
10929 void __fastcall TInterface::OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
10930 {
10931  if((Button == mbRight) && Level2OperMode == Operating)
10932  {
10933  OutputLog10->Caption = "";
10934  }
10935 }
10936 
10937 // ---------------------------------------------------------------------------
10938 
10939 void __fastcall TInterface::AboutMenuItemClick(TObject *Sender)
10940 {
10941  try
10942  {
10943  if((Level1Mode == OperMode) && (Level2OperMode != PreStart))
10944  // if PreStart leave as is [Modified at v1.2.0 - formerly just 'if((Level1Mode == OperMode)']
10945  {
10947  SetLevel2OperMode(3);
10948  MasterClock->Enabled = false;
10949  }
10950  AboutForm->ShowModal();
10951  }
10952  catch(const Exception &e)
10953  {
10954  ErrorLog(168, e.Message);
10955  }
10956 }
10957 
10958 // ---------------------------------------------------------------------------
10959 
10960 void __fastcall TInterface::OpenHelpMenuItemClick(TObject *Sender)
10961 {
10962  try
10963  {
10964  // Helpfile allocated during construction of Interface
10965  Application->HelpKeyword(u"Introduction"); // added at v2.0.0 for .chm help file
10966  }
10967  catch(const Exception &e)
10968  {
10969  ErrorLog(175, e.Message);
10970  }
10971 }
10972 
10973 // ---------------------------------------------------------------------------
10974 
10975 void __fastcall TInterface::RailwayWebSiteMenuItemClick(TObject *Sender)
10976 {
10977  const UnicodeString Link = "http://www.railwayoperationsimulator.com";
10978  ::ShellExecute(Handle, NULL, (Link).c_str(), NULL, NULL, SW_SHOWNORMAL);
10979 }
10980 
10981 // ---------------------------------------------------------------------------
10982 
10983 void __fastcall TInterface::BlackBgndMenuItemClick(TObject *Sender)
10984 {
10985  try
10986  {
10987  TrainController->LogEvent("BlackBgndMenuItemClick");
10988  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlackBgndMenuItemClick");
10989  std::ofstream ColFile((CurDir + "\\Background.col").c_str());
10990  if(ColFile.fail())
10991  {
10992  // ShowMessage("Failed to store colour file, program will default to a black background when next loaded");
10993  // no need for message as will revert to black by default
10994  }
10995  else
10996  {
10997  Utilities->SaveFileString(ColFile, "black");
10998  ColFile.close(); // added at v2.3.0, should have been in earlier
10999  }
11000  TColor OldTransparentColour = Utilities->clTransparent;
11001  Utilities->clTransparent = TColor(0);
11002  SelectBitmap->TransparentColor = Utilities->clTransparent;
11004  TextBox->Color = clB3G3R3;
11006 
11007  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
11008  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
11009  Level1Mode = BaseMode;
11010  SetLevel1Mode(128);
11011  Utilities->CallLogPop(1797);
11012  }
11013  catch(const Exception &e)
11014  {
11015  ErrorLog(170, e.Message);
11016  }
11017 }
11018 
11019 // ---------------------------------------------------------------------------
11020 
11021 void __fastcall TInterface::WhiteBgndMenuItemClick(TObject *Sender)
11022 {
11023  try
11024  {
11025  TrainController->LogEvent("WhiteBgndMenuItemClick");
11026  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",WhiteBgndMenuItemClick");
11027  std::ofstream ColFile((CurDir + "\\Background.col").c_str());
11028  if(ColFile.fail())
11029  {
11030  ShowMessage("Failed to store colour file, program will default to a black background when next loaded");
11031  }
11032  else
11033  {
11034  Utilities->SaveFileString(ColFile, "white");
11035  ColFile.close(); // added at v2.3.0, should have been in earlier
11036  }
11037  TColor OldTransparentColour = Utilities->clTransparent;
11038  Utilities->clTransparent = TColor(0xFFFFFF);
11039  SelectBitmap->TransparentColor = Utilities->clTransparent;
11041  TextBox->Color = clB5G5R5;
11043 
11044  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
11045  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
11046  Level1Mode = BaseMode;
11047  SetLevel1Mode(129);
11048  Utilities->CallLogPop(1798);
11049  }
11050  catch(const Exception &e)
11051  {
11052  ErrorLog(171, e.Message);
11053  }
11054 }
11055 
11056 // ---------------------------------------------------------------------------
11057 
11058 void __fastcall TInterface::BlueBgndMenuItemClick(TObject *Sender)
11059 {
11060  try
11061  {
11062  TrainController->LogEvent("BlueBgndMenuItemClick");
11063  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",BlueBgndMenuItemClick");
11064  std::ofstream ColFile((CurDir + "\\Background.col").c_str());
11065  if(ColFile.fail())
11066  {
11067  ShowMessage("Failed to store colour file, program will default to a black background when next loaded");
11068  }
11069  else
11070  {
11071  Utilities->SaveFileString(ColFile, "blue");
11072  ColFile.close(); // added at v2.3.0, should have been in earlier
11073  }
11074  TColor OldTransparentColour = Utilities->clTransparent;
11075  Utilities->clTransparent = TColor(0x330000);
11076  SelectBitmap->TransparentColor = Utilities->clTransparent;
11078  TextBox->Color = clB3G3R3;
11080 
11081  MainScreen->Canvas->Brush->Color = Utilities->clTransparent;
11082  MainScreen->Canvas->FillRect(MainScreen->ClientRect);
11083  Level1Mode = BaseMode;
11084  SetLevel1Mode(130);
11085  Utilities->CallLogPop(1799);
11086  }
11087  catch(const Exception &e)
11088  {
11089  ErrorLog(172, e.Message);
11090  }
11091 }
11092 
11093 // ---------------------------------------------------------------------------
11094 
11095 void __fastcall TInterface::SpeedToggleButtonClick(TObject *Sender)
11096 {
11097  if(SpeedTopLabel->Caption == "mph")
11098  {
11099  SpeedTopLabel->Caption = "km/h";
11100  SpeedBottomLabel->Caption = "mph";
11101  }
11102  else
11103  {
11104  SpeedTopLabel->Caption = "mph";
11105  SpeedBottomLabel->Caption = "km/h";
11106  }
11107  // swap values to match toggle state
11108  UnicodeString SavedTopValue = SpeedEditBox->Text;
11109  UnicodeString SavedBottomValue = SpeedVariableLabel->Caption;
11110 
11111  SpeedEditBox->Text = SavedBottomValue;
11112  SpeedVariableLabel->Caption = SavedTopValue;
11113 }
11114 // ---------------------------------------------------------------------------
11115 
11116 void __fastcall TInterface::SpeedToggleButton2Click(TObject *Sender)
11117 {
11118  if(SpeedTopLabel2->Caption == "mph")
11119  {
11120  SpeedTopLabel2->Caption = "km/h";
11121  SpeedBottomLabel2->Caption = "mph";
11122  }
11123  else
11124  {
11125  SpeedTopLabel2->Caption = "mph";
11126  SpeedBottomLabel2->Caption = "km/h";
11127  }
11128  // swap values to match toggle state
11129  UnicodeString SavedTopValue = SpeedEditBox2->Text;
11130  UnicodeString SavedBottomValue = SpeedVariableLabel2->Caption;
11131 
11132  SpeedEditBox2->Text = SavedBottomValue;
11133  SpeedVariableLabel2->Caption = SavedTopValue;
11134 }
11135 // ---------------------------------------------------------------------------
11136 
11137 void __fastcall TInterface::SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11138 {
11139  try
11140  {
11141  TrainController->LogEvent("SpeedEditBoxKeyUp," + AnsiString(Key));
11142  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBoxKeyUp," + AnsiString(Key));
11143  bool ErrorFlag = false, TooBigFlag = false;
11144  if(SpeedEditBox->Text.Length() > 0)
11145  {
11146  if(SpeedEditBox->Text.Length() > 5)
11147  {
11148  TooBigFlag = true;
11149  }
11150  for(int x = 1; x <= SpeedEditBox->Text.Length(); x++)
11151  {
11152  if((SpeedEditBox->Text[x] < '0') || (SpeedEditBox->Text[x] > '9'))
11153  {
11154  SpeedVariableLabel->Caption = "Entry error";
11155  ErrorFlag = true;
11156  break;
11157  }
11158  if(TooBigFlag)
11159  {
11160  SpeedVariableLabel->Caption = "Too big";
11161  break;
11162  }
11163  }
11164  if(!ErrorFlag && !TooBigFlag)
11165  {
11166 /*
11167  1 mph = 1.609344 km/h
11168  1 km/h = 0.621371 mph
11169 */
11170  if(SpeedTopLabel->Caption == "mph")
11171  {
11172  // do mph-to-km/h conversion
11173  int MPH = SpeedEditBox->Text.ToInt();
11174  int KPH = (MPH * 1.609344) + 0.5;
11175  SpeedVariableLabel->Caption = UnicodeString(KPH);
11176  }
11177  else
11178  {
11179  // do km/h-to-mph conversion
11180  int KPH = SpeedEditBox->Text.ToInt();
11181  int MPH = (KPH * 0.621371) + 0.5;
11182  SpeedVariableLabel->Caption = UnicodeString(MPH);
11183  }
11184  }
11185  }
11186  else
11187  {
11188  SpeedVariableLabel->Caption = "";
11189  }
11190  Utilities->CallLogPop(1865);
11191  }
11192  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11193  {
11194  SpeedVariableLabel->Caption = "Entry error";
11195  }
11196  catch(const Exception &e)
11197  {
11198  ErrorLog(176, e.Message);
11199  }
11200 }
11201 
11202 // ---------------------------------------------------------------------------
11203 
11204 void __fastcall TInterface::PowerToggleButtonClick(TObject *Sender)
11205 {
11206  if(PowerTopLabel->Caption == "HP")
11207  {
11208  PowerTopLabel->Caption = "kW";
11209  PowerBottomLabel->Caption = "HP";
11210  }
11211  else
11212  {
11213  PowerTopLabel->Caption = "HP";
11214  PowerBottomLabel->Caption = "kW";
11215  }
11216  // swap values to match toggle state
11217  UnicodeString SavedTopValue = PowerEditBox->Text;
11218  UnicodeString SavedBottomValue = PowerVariableLabel->Caption;
11219 
11220  PowerEditBox->Text = SavedBottomValue;
11221  PowerVariableLabel->Caption = SavedTopValue;
11222 }
11223 // ---------------------------------------------------------------------------
11224 
11225 void __fastcall TInterface::PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11226 {
11227  try
11228  {
11229  TrainController->LogEvent("PowerEditBoxKeyUp," + AnsiString(Key));
11230  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PowerEditBoxKeyUp," + AnsiString(Key));
11231  bool ErrorFlag = false, TooBigFlag = false;
11232  if(PowerEditBox->Text.Length() > 0)
11233  {
11234  if(PowerEditBox->Text.Length() > 8)
11235  {
11236  TooBigFlag = true;
11237  }
11238  for(int x = 1; x <= PowerEditBox->Text.Length(); x++)
11239  {
11240  if((PowerEditBox->Text[x] < '0') || (PowerEditBox->Text[x] > '9'))
11241  {
11242  PowerVariableLabel->Caption = "Entry error";
11243  ErrorFlag = true;
11244  break;
11245  }
11246  if(TooBigFlag)
11247  {
11248  PowerVariableLabel->Caption = "Too big";
11249  break;
11250  }
11251  }
11252  if(!ErrorFlag && !TooBigFlag)
11253  {
11254 /*
11255  1 kW = 1.340482574 HP
11256  1 HP = 0.745699872 kW
11257 */
11258  if(PowerTopLabel->Caption == "HP")
11259  {
11260  // do HP-to-kW conv
11261  int HP = PowerEditBox->Text.ToInt();
11262  int KW = (HP * 0.745699872) + 0.5;
11263  PowerVariableLabel->Caption = UnicodeString(KW);
11264  }
11265  else
11266  {
11267  // do kW-to-HP conv
11268  int KW = PowerEditBox->Text.ToInt();
11269  int HP = (KW * 1.340482574) + 0.5;
11270  PowerVariableLabel->Caption = UnicodeString(HP);
11271  }
11272  }
11273  }
11274  else
11275  {
11276  PowerVariableLabel->Caption = "";
11277  }
11278  Utilities->CallLogPop(1868);
11279  }
11280  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11281  {
11282  PowerVariableLabel->Caption = "Entry error";
11283  }
11284  catch(const Exception &e)
11285  {
11286  ErrorLog(179, e.Message);
11287  }
11288 }
11289 // ---------------------------------------------------------------------------
11290 
11291 void __fastcall TInterface::SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11292 {
11293  try
11294  {
11295  TrainController->LogEvent("SpeedEditBox2KeyUp," + AnsiString(Key));
11296  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SpeedEditBox2KeyUp," + AnsiString(Key));
11297  bool ErrorFlag = false, TooBigFlag = false;
11298  if(SpeedEditBox2->Text.Length() > 0)
11299  {
11300  if(SpeedEditBox2->Text.Length() > 5)
11301  {
11302  TooBigFlag = true;
11303  }
11304  for(int x = 1; x <= SpeedEditBox2->Text.Length(); x++)
11305  {
11306  if((SpeedEditBox2->Text[x] < '0') || (SpeedEditBox2->Text[x] > '9'))
11307  {
11308  SpeedVariableLabel2->Caption = "Entry error";
11309  ErrorFlag = true;
11310  break;
11311  }
11312  if(TooBigFlag)
11313  {
11314  SpeedVariableLabel2->Caption = "Too big";
11315  break;
11316  }
11317  }
11318  if(!ErrorFlag && !TooBigFlag)
11319  {
11320 /*
11321  1 mph = 1.609344 km/h
11322  1 km/h = 0.621371 mph
11323 */
11324  if(SpeedTopLabel2->Caption == "mph")
11325  {
11326  // do mph-to-km/h conversion
11327  int MPH = SpeedEditBox2->Text.ToInt();
11328  int KPH = (MPH * 1.609344) + 0.5;
11329  SpeedVariableLabel2->Caption = AnsiString(KPH);
11330  }
11331  else
11332  {
11333  // do km/h-to-mph conversion
11334  int KPH = SpeedEditBox2->Text.ToInt();
11335  int MPH = (KPH * 0.621371) + 0.5;
11336  SpeedVariableLabel2->Caption = AnsiString(MPH);
11337  }
11338  }
11339  }
11340  else
11341  {
11342  SpeedVariableLabel2->Caption = "";
11343  }
11344  Utilities->CallLogPop(1866);
11345  }
11346  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11347  {
11348  SpeedVariableLabel2->Caption = "Entry error";
11349  }
11350  catch(const Exception &e)
11351  {
11352  ErrorLog(177, e.Message);
11353  }
11354 }
11355 
11356 // ---------------------------------------------------------------------------
11357 
11358 void __fastcall TInterface::LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11359 {
11360  try
11361  {
11362  TrainController->LogEvent("LengthEditKeyUp," + AnsiString(Key));
11363  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",LengthEditKeyUp," + AnsiString(Key));
11364  bool ErrorFlag = false, TooLongFlag = false;
11365  if((MileEdit->Text.Length() > 0) && (MileEdit->Text.Length() < 6))
11366  {
11367  for(int x = 1; x <= MileEdit->Text.Length(); x++)
11368  {
11369  if((MileEdit->Text[x] < '0') || (MileEdit->Text[x] > '9'))
11370  {
11371  MetreVariableLabel->Caption = "Entry error";
11372  ErrorFlag = true;
11373  break;
11374  }
11375  }
11376  }
11377  if((ChainEdit->Text.Length() > 0) && (ChainEdit->Text.Length() < 6))
11378  {
11379  for(int x = 1; x <= ChainEdit->Text.Length(); x++)
11380  {
11381  if((ChainEdit->Text[x] < '0') || (ChainEdit->Text[x] > '9'))
11382  {
11383  MetreVariableLabel->Caption = "Entry error";
11384  ErrorFlag = true;
11385  break;
11386  }
11387  }
11388  }
11389  if((YardEdit->Text.Length() > 0) && (YardEdit->Text.Length() < 6))
11390  {
11391  for(int x = 1; x <= YardEdit->Text.Length(); x++)
11392  {
11393  if((YardEdit->Text[x] < '0') || (YardEdit->Text[x] > '9'))
11394  {
11395  MetreVariableLabel->Caption = "Entry error";
11396  ErrorFlag = true;
11397  break;
11398  }
11399  }
11400  }
11401  if((MileEdit->Text.Length() > 5) || (ChainEdit->Text.Length() > 5) || (YardEdit->Text.Length() > 5))
11402  {
11403  TooLongFlag = true;
11404  MetreVariableLabel->Caption = "Too big";
11405  }
11406  if(!ErrorFlag && !TooLongFlag)
11407  {
11408  int Miles = 0, Chains = 0, Yards = 0, Metres = 0;
11409  if(MileEdit->Text.Length() > 0)
11410  {
11411  Miles = MileEdit->Text.ToInt();
11412  }
11413  if(ChainEdit->Text.Length() > 0)
11414  {
11415  Chains = ChainEdit->Text.ToInt();
11416  }
11417  if(YardEdit->Text.Length() > 0)
11418  {
11419  Yards = YardEdit->Text.ToInt();
11420  }
11421  Metres = int((Miles * 1609.344) + (Chains * 20.1168) + (Yards * 0.9144) + 0.5);
11422  MetreVariableLabel->Caption = AnsiString(Metres);
11423  }
11424  if((MileEdit->Text.Length() == 0) && (ChainEdit->Text.Length() == 0) && (YardEdit->Text.Length() == 0))
11425  {
11426  MetreVariableLabel->Caption = "";
11427  }
11428  Utilities->CallLogPop(1867);
11429  }
11430  catch(const EConvertError &ec) // thrown for ToInt() conversion error; shouldn't occur but include to prevent a crash
11431  {
11432  MetreVariableLabel->Caption = "Entry error";
11433  }
11434  catch(const Exception &e)
11435  {
11436  ErrorLog(178, e.Message);
11437  }
11438 }
11439 
11440 // ---------------------------------------------------------------------------
11441 
11442 void __fastcall TInterface::TTClockAdjButtonClick(TObject *Sender)
11443 {
11444  try
11445  {
11446  TrainController->LogEvent("TTClockAdjButtonClick");
11447  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjButtonClick");
11448 // Utilities->Clock2Stopped = true; // to keep panel buttons disabled, restarted on exit
11449  Display->HideWarningLog(0); //because this panel overwrites it
11450  TTClockAdjPanel->Visible = true;
11451  TTClockAdjButton->Enabled = false;
11452 /*
11453  OperatingPanelLabel->Caption = "Disabled"; all these now dealt with in ClockTimer2
11454  OperatingPanel->Enabled = false;
11455  ZoomButton->Enabled = false;
11456  HomeButton->Enabled = false;
11457  NewHomeButton->Enabled = false;
11458  ScreenLeftButton->Enabled = false;
11459  ScreenRightButton->Enabled = false;
11460  ScreenUpButton->Enabled = false;
11461  ScreenDownButton->Enabled = false;
11462 */
11463  Utilities->CallLogPop(1875);
11464  }
11465  catch(const Exception &e)
11466  {
11467  ErrorLog(181, e.Message);
11468  }
11469 }
11470 
11471 // ---------------------------------------------------------------------------
11472 
11473 void __fastcall TInterface::TTClockExitButtonClick(TObject *Sender)
11474 {
11475  try
11476  {
11477  TrainController->LogEvent("TTClockExitButtonClick");
11478  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockExitButtonClick");
11479  TTClockAdjPanel->Visible = false;
11480  TTClockAdjButton->Enabled = true;
11481 /* these dealt with in ClockTimer2
11482  ZoomButton->Enabled = true;
11483  HomeButton->Enabled = true;
11484  NewHomeButton->Enabled = true;
11485  ScreenLeftButton->Enabled = true;
11486  ScreenRightButton->Enabled = true;
11487  ScreenUpButton->Enabled = true;
11488  ScreenDownButton->Enabled = true;
11489  OperatingPanel->Enabled = true;
11490  OperatingPanelLabel->Caption = "Operation";
11491 */
11492  Display->ShowWarningLog(0);
11493  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
11494  if((TTClockSpeed != PauseEntryTTClockSpeed) || (TTClockTimeChange > 0.000347))
11495  // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
11497  {
11498  TTClockAdjustWarningPanel->Top = MainScreen->Top + ((MainScreen->Height - TTClockAdjustWarningPanel->Height)/2);
11499  TTClockAdjustWarningPanel->Left = MainScreen->Left + ((MainScreen->Width - TTClockAdjustWarningPanel->Width)/2);
11500  TTClockAdjustWarningLabel->Caption =
11501  "Changes have been made to the timetable clock - you may wish to save a session before resuming operation.\n\nTo cancel all changes re-click the 'Adjust the timetable clock' button then click the reset button BEFORE resuming operation.";
11502  TTClockAdjustWarningPanel->Visible = true;
11503  }
11504 // Utilities->Clock2Stopped = false; // as above
11505  LastNonCtrlOrShiftKeyDown = -1; //to restore the ability to reselect T after adj panel hidden (FormKeyUp doesn't work because the Interface form doesn't have focus)
11506  Utilities->CallLogPop(1876);
11507  }
11508  catch(const Exception &e)
11509  {
11510  ErrorLog(182, e.Message);
11511  }
11512 }
11513 // ---------------------------------------------------------------------------
11514 
11515 void __fastcall TInterface::TTClockx2ButtonClick(TObject *Sender)
11516 {
11517  try
11518  {
11519  TrainController->LogEvent("TTClockx2ButtonClick");
11520  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx2ButtonClick");
11521  TTClockSpeed = 2;
11522  TTClockSpeedLabel->Caption = "x2";
11524  Utilities->CallLogPop(1878);
11525  }
11526  catch(const Exception &e)
11527  {
11528  ErrorLog(184, e.Message);
11529  }
11530 }
11531 
11532 // ---------------------------------------------------------------------------
11533 
11534 void __fastcall TInterface::TTClockx4ButtonClick(TObject *Sender)
11535 {
11536  try
11537  {
11538  TrainController->LogEvent("TTClockx4ButtonClick");
11539  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx4ButtonClick");
11540  TTClockSpeed = 4;
11541  TTClockSpeedLabel->Caption = "x4";
11543  Utilities->CallLogPop(1883);
11544  }
11545  catch(const Exception &e)
11546  {
11547  ErrorLog(189, e.Message);
11548  }
11549 }
11550 
11551 // ---------------------------------------------------------------------------
11552 
11553 void __fastcall TInterface::TTClockx8ButtonClick(TObject *Sender)
11554 {
11555  try
11556  {
11557  TrainController->LogEvent("TTClockx8ButtonClick");
11558  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx8ButtonClick");
11559  TTClockSpeed = 8;
11560  TTClockSpeedLabel->Caption = "x8";
11562  Utilities->CallLogPop(1884);
11563  }
11564  catch(const Exception &e)
11565  {
11566  ErrorLog(190, e.Message);
11567  }
11568 }
11569 
11570 // ---------------------------------------------------------------------------
11571 
11572 void __fastcall TInterface::TTClockx16ButtonClick(TObject *Sender)
11573 {
11574  try
11575  {
11576  TrainController->LogEvent("TTClockx16ButtonClick");
11577  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx16ButtonClick");
11578  TTClockSpeed = 16;
11579  TTClockSpeedLabel->Caption = "x16";
11581  Utilities->CallLogPop(1885);
11582  }
11583  catch(const Exception &e)
11584  {
11585  ErrorLog(191, e.Message);
11586  }
11587 }
11588 
11589 // ---------------------------------------------------------------------------
11590 
11591 void __fastcall TInterface::TTClockx1ButtonClick(TObject *Sender)
11592 {
11593  try
11594  {
11595  TrainController->LogEvent("TTClockx1ButtonClick");
11596  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockx1ButtonClick");
11597  TTClockSpeed = 1;
11598  TTClockSpeedLabel->Caption = "x1";
11600  Utilities->CallLogPop(1886);
11601  }
11602  catch(const Exception &e)
11603  {
11604  ErrorLog(192, e.Message);
11605  }
11606 }
11607 
11608 // ---------------------------------------------------------------------------
11609 
11610 void __fastcall TInterface::TTClockxHalfButtonClick(TObject *Sender)
11611 {
11612  try
11613  {
11614  TrainController->LogEvent("TTClockxHalfButtonClick");
11615  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxHalfButtonClick");
11616  TTClockSpeed = 0.5;
11617  TTClockSpeedLabel->Caption = "x1/2";
11619  Utilities->CallLogPop(1887);
11620  }
11621  catch(const Exception &e)
11622  {
11623  ErrorLog(193, e.Message);
11624  }
11625 }
11626 
11627 // ---------------------------------------------------------------------------
11628 
11629 void __fastcall TInterface::TTClockxQuarterButtonClick(TObject *Sender)
11630 {
11631  try
11632  {
11633  TrainController->LogEvent("TTClockxQuarterButtonClick");
11634  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxQuarterButtonClick");
11635  TTClockSpeed = 0.25;
11636  TTClockSpeedLabel->Caption = "x1/4";
11638  Utilities->CallLogPop(1888);
11639  }
11640  catch(const Exception &e)
11641  {
11642  ErrorLog(194, e.Message);
11643  }
11644 }
11645 
11646 // ---------------------------------------------------------------------------
11647 
11648 void __fastcall TInterface::TTClockxEighthButtonClick(TObject *Sender)
11649 { // added for v2.3.0 for very big railways
11650  try
11651  {
11652  TrainController->LogEvent("TTClockxEighthButtonClick");
11653  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxEighthButtonClick");
11654  TTClockSpeed = 0.125;
11655  TTClockSpeedLabel->Caption = "x1/8";
11657  Utilities->CallLogPop(2099);
11658  }
11659  catch(const Exception &e)
11660  {
11661  ErrorLog(203, e.Message);
11662  }
11663 }
11664 // ---------------------------------------------------------------------------
11665 
11666 void __fastcall TInterface::TTClockxSixteenthButtonClick(TObject *Sender)
11667 { // added for v2.3.0 for very big railways
11668  try
11669  {
11670  TrainController->LogEvent("TTClockxSixteenthButtonClick");
11671  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockxSixteenthButtonClick");
11672  TTClockSpeed = 0.0625;
11673  TTClockSpeedLabel->Caption = "x1/16";
11675  Utilities->CallLogPop(2100);
11676  }
11677  catch(const Exception &e)
11678  {
11679  ErrorLog(204, e.Message);
11680  }
11681 }
11682 
11683 // ---------------------------------------------------------------------------
11684 
11685 void __fastcall TInterface::TTClockAdd1hButtonClick(TObject *Sender)
11686 {
11687  try
11688  {
11689  TrainController->LogEvent("TTClockAdd1hButtonClick");
11690  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1hButtonClick");
11691  double TTClockIncrement = 1.0 / 24;
11692  TrainController->RestartTime += TDateTime(TTClockIncrement);
11695  Utilities->CallLogPop(1879);
11696  }
11697  catch(const Exception &e)
11698  {
11699  ErrorLog(185, e.Message);
11700  }
11701 }
11702 
11703 // ---------------------------------------------------------------------------
11704 
11705 void __fastcall TInterface::TTClockAdd10mButtonClick(TObject *Sender)
11706 {
11707  try
11708  {
11709  TrainController->LogEvent("TTClockAdd10mButtonClick");
11710  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd10mButtonClick");
11711  double TTClockIncrement = 1.0 / 144;
11712  TrainController->RestartTime += TDateTime(TTClockIncrement);
11715  Utilities->CallLogPop(1881);
11716  }
11717  catch(const Exception &e)
11718  {
11719  ErrorLog(187, e.Message);
11720  }
11721 }
11722 
11723 // ---------------------------------------------------------------------------
11724 
11725 void __fastcall TInterface::TTClockAdd1mButtonClick(TObject *Sender)
11726 {
11727  try
11728  {
11729  TrainController->LogEvent("TTClockAdd1mButtonClick");
11730  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdd1mButtonClick");
11731  double TTClockIncrement = 1.0 / 1440;
11732  TrainController->RestartTime += TDateTime(TTClockIncrement);
11735  Utilities->CallLogPop(1882);
11736  }
11737  catch(const Exception &e)
11738  {
11739  ErrorLog(188, e.Message);
11740  }
11741 }
11742 
11743 // ---------------------------------------------------------------------------
11744 
11745 void __fastcall TInterface::TTClockResetButtonClick(TObject *Sender)
11746 {
11747  try
11748  {
11749  TrainController->LogEvent("TTClockResetButtonClick");
11750  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockResetButtonClick");
11755  if(TTClockSpeed == 2)
11756  TTClockSpeedLabel->Caption = "x2";
11757  else if(TTClockSpeed == 4)
11758  TTClockSpeedLabel->Caption = "x4";
11759  else if(TTClockSpeed == 8)
11760  TTClockSpeedLabel->Caption = "x8";
11761  else if(TTClockSpeed == 16)
11762  TTClockSpeedLabel->Caption = "x16";
11763  else if(TTClockSpeed == 0.5)
11764  TTClockSpeedLabel->Caption = "x1/2";
11765  else if(TTClockSpeed == 0.25)
11766  TTClockSpeedLabel->Caption = "x1/4";
11767  else if(TTClockSpeed == 0.125)
11768  TTClockSpeedLabel->Caption = "x1/8";
11769  else if(TTClockSpeed == 0.0625)
11770  TTClockSpeedLabel->Caption = "x1/16";
11771  else
11772  {
11773  TTClockSpeed = 1;
11774  TTClockSpeedLabel->Caption = "x1";
11775  }
11776  Utilities->CallLogPop(1880);
11777  }
11778  catch(const Exception &e)
11779  {
11780  ErrorLog(186, e.Message);
11781  }
11782 }
11783 
11784 // ---------------------------------------------------------------------------
11785 
11786 void __fastcall TInterface::PresetAutoSigRoutesButtonClick(TObject *Sender)
11787 {
11788  try
11789  {
11790  TrainController->LogEvent("PresetAutoSigRoutesButtonClick");
11791  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PresetAutoSigRoutesButtonClick");
11792  InfoPanel->Caption = "PRE-START: Presetting automatic signal routes";
11793  OperatingPanelLabel->Caption = "Disabled";
11794  OperatingPanel->Enabled = false; // becomes re-enabled during the call to ClockTimer2
11795  ZoomButton->Enabled = false;
11796  HomeButton->Enabled = false;
11797  NewHomeButton->Enabled = false;
11798  ScreenLeftButton->Enabled = false;
11799  ScreenRightButton->Enabled = false;
11800  ScreenUpButton->Enabled = false;
11801  ScreenDownButton->Enabled = false;
11802 
11803  Screen->Cursor = TCursor(-11); // Hourglass
11804  TPrefDirElement StartElement, EndElement;
11805  bool PointsChanged, AtLeastOneSet = false;
11806  int LastIteratorValue = 0;
11807  while(true)
11808  {
11809  if(!EveryPrefDir->GetStartAndEndPrefDirElements(0, StartElement, EndElement, LastIteratorValue))
11810  break;
11811  // rest of routine here - i.e. build the routes
11812  ConstructRoute->ClearRoute(); // in case not empty though should be
11813  AtLeastOneSet = true;
11814  if(ConstructRoute->GetPreferredRouteStartElement(1, StartElement.HLoc, StartElement.VLoc, EveryPrefDir, true, true))
11815  // true for both ConsecSignalsRoute & AutoSigsFlag
11816  {}
11817  if(ConstructRoute->GetNextPreferredRouteElement(1, EndElement.HLoc, EndElement.VLoc, EveryPrefDir, true, true, ConstructRoute->ReqPosRouteID,
11818  PointsChanged))
11819  {}
11821  }
11822  if(AtLeastOneSet)
11823  {
11826  }
11827  else
11828  {
11829  ShowMessage("No presettable automatic signal routes are available");
11830  }
11831  Screen->Cursor = TCursor(-2); // Arrow
11832  Utilities->CallLogPop(1994);
11833  }
11834  catch(const Exception &e)
11835  {
11836  ErrorLog(195, e.Message);
11837  }
11838 }
11839 
11840 // ---------------------------------------------------------------------------
11841 
11842 void __fastcall TInterface::FormResize(TObject *Sender) // new at v2.1.0
11843 {
11844  try
11845  {
11846  if(!SkipFormResizeEvent) // to avoid calling during startup and especially during shutdown
11847  { // else fails on shutdown because HiddenScreen & other things no longer exist
11848  int DispW = (Interface->Width - 64 - 16) / 16;
11849 // will truncate down to a multiple of 16 (64 = side panels and 16 compensates for excess width of Interface)
11850  int DispH = (Interface->Height - 192) / 16;
11851  MainScreen->Width = DispW * 16;
11852  MainScreen->Height = DispH * 16;
11853  Utilities->ScreenElementWidth = DispW;
11854  Utilities->ScreenElementHeight = DispH;
11855  HiddenScreen->Width = MainScreen->Width;
11856  HiddenScreen->Height = MainScreen->Height;
11857  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
11858  PerformancePanel->Left = MainScreen->Left;
11859  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new at v2.2.0
11860  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width;
11861  SigImagePanel->Left = (Interface->Width - SigImagePanel->Width) / 2; // added for v2.3.0
11862  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height; // new v2.2.0
11863  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width; // new v2.2.0
11864  MTBFEditBox->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 32; // new v2.4.0 32 is to place it above the positional panel
11865  MTBFLabel->Left = MainScreen->Left + MainScreen->Width - MTBFEditBox->Width + 30 - 55; // new v2.4.0 placed above and to the left of MTBFEditBox
11866  PositionalPanel->Left = MainScreen->Left + MainScreen->Width; // changed at v2.4.0
11867  PositionalPanel->Top = MainScreen->Top; // changed at v2.4.0
11868  PositionalPanel->Height = MainScreen->Height; // changed at v2.4.0
11869 
11870  if(!Display->ZoomOutFlag)
11871  {
11873  }
11874  else
11875  {
11876  Display->ClearDisplay(11);
11878  }
11879  Display->Update();
11880  }
11881  }
11882  catch(const Exception &e)
11883  {
11884  ErrorLog(197, e.Message);
11885  }
11886 }
11887 
11888 // ---------------------------------------------------------------------------
11889 
11890 void __fastcall TInterface::OperatorActionButtonClick(TObject *Sender)
11891 {
11892  try
11893  {
11894  TrainController->LogEvent("OperatorActionButtonClick");
11895  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",OperatorActionButtonClick");
11897  {
11898  ShowOperatorActionPanel = true;
11899  OperatorActionPanel->Visible = true;
11901  OperatorActionButton->Glyph->LoadFromResourceName(0, "HideOpActionPanel");
11902  }
11903  else
11904  {
11905  ShowOperatorActionPanel = false;
11906  OperatorActionPanel->Visible = false;
11908  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel");
11909  }
11910  Utilities->CallLogPop(2073);
11911  }
11912  catch(const Exception &e)
11913  {
11914  ErrorLog(199, e.Message);
11915  }
11916 }
11917 
11918 // ---------------------------------------------------------------------------
11919 
11921 {
11922  try
11923  {
11924  TrainController->LogEvent("ConverttoRightHandSignalsMenuItemClick");
11925  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConverttoRightHandSignalsMenuItemClick");
11927  if(Utilities->RHSignalFlag) // RH sigs after conversion
11928  {
11929  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Left Hand Signals";
11931  {
11933  }
11934  else
11935  {
11937  }
11938  SigImagePanel->Caption = "Signals will be on the right hand side of the track";
11939  SigsOnLeftImage1->Visible = false;
11940  SigsOnLeftImage2->Visible = false;
11941  SigsOnRightImage1->Visible = true;
11942  SigsOnRightImage2->Visible = true;
11943  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
11944  if(SigFile.fail())
11945  {
11946  ShowMessage("Failed to store right hand signal setting, program will default to left hand signals when next loaded");
11947  }
11948  else
11949  {
11950  Utilities->SaveFileString(SigFile, "RHSignals");
11951  }
11952  }
11953  else // LH sigs after conversion
11954  {
11955  ConverttoRightHandSignalsMenuItem->Caption = "Convert to Right Hand Signals";
11957  {
11959  }
11960  else
11961  {
11963  }
11964  SigImagePanel->Caption = "Signals will be on the left hand side of the track";
11965  SigsOnRightImage1->Visible = false;
11966  SigsOnRightImage2->Visible = false;
11967  SigsOnLeftImage1->Visible = true;
11968  SigsOnLeftImage2->Visible = true;
11969  std::ofstream SigFile((CurDir + "\\Signal.hnd").c_str());
11970  if(SigFile.fail())
11971  {
11972  // no need for message as will default to LH: ShowMessage("Failed to store left hand signal setting, program will default to left hand signals when next loaded");
11973  }
11974  else
11975  {
11976  Utilities->SaveFileString(SigFile, "LHSignals");
11977  }
11978  }
11979  Utilities->CallLogPop(2097);
11980  }
11981  catch(const Exception &e)
11982  {
11983  ErrorLog(202, e.Message);
11984  }
11985 }
11986 // ---------------------------------------------------------------------------
11987 
11988 void __fastcall TInterface::MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
11989 
11990 {
11991  try
11992  {
11993  TrainController->LogEvent("MTBFEditBoxKeyUp," + AnsiString(Key));
11994  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxKeyUp," + AnsiString(Key));
11995  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
11996  {
11997  Utilities->CallLogPop(2160);
11998  return;
11999  }
12000  bool TooBigFlag = false, BadCharsFlag = false;
12003  if(MTBFEditBox->Text.Length() > 0)
12004  {
12005  for(int x = 1; x <= MTBFEditBox->Text.Length(); x++)
12006  {
12007  if((MTBFEditBox->Text[x] < '0') || (MTBFEditBox->Text[x] > '9'))
12008  {
12009  BadCharsFlag = true;
12010  break;
12011  }
12012  }
12013  if(!BadCharsFlag)
12014  {
12015  if(StrToInt(MTBFEditBox->Text) > 10000)
12016  {
12017  TooBigFlag = true;
12018  }
12019  }
12020  if(TooBigFlag)
12021  {
12022  ShowMessage("Maximum value allowed is 10,000");
12023  MTBFEditBox->Text = "";
12026  Utilities->CallLogPop(2161);
12027  return;
12028  }
12029  if(BadCharsFlag)
12030  {
12031  ShowMessage("Value must be a whole number with no special characters");
12032  MTBFEditBox->Text = "";
12035  Utilities->CallLogPop(2162);
12036  return;
12037  }
12038  TrainController->AvHoursIntValue = StrToInt(MTBFEditBox->Text); // ok if user enters 0 as that means no failures
12040  }
12042  {
12043  MTBFEditBox->Text = "";
12045  }
12046  Utilities->CallLogPop(2163);
12047  }
12048  catch(const Exception &e)
12049  {
12050  ErrorLog(209, e.Message);
12051  }
12052 }
12053 
12054 // ---------------------------------------------------------------------------
12055 
12056 void __fastcall TInterface::MTBFEditBoxClick(TObject *Sender)
12057 {
12058  try
12059  {
12060  TrainController->LogEvent("MTBFEditBoxClick");
12061  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
12062  if((Level1Mode != OperMode) || (Level2OperMode != PreStart))
12063  {
12064  MTBFEditBox->ReadOnly = true; // it should be anyway but include here for safety
12066  "Values can only be entered or changed in Pre-Start mode\ni.e. after selecting 'Operate railway' but before clicking 'Run'");
12067  }
12068  Utilities->CallLogPop(2164);
12069  }
12070  catch(const Exception &e)
12071  {
12072  ErrorLog(210, e.Message);
12073  }
12074 }
12075 
12076 // ---------------------------------------------------------------------------
12077 
12078 void __fastcall TInterface::UserGraphicButtonClick(TObject *Sender)
12079 {
12080  try
12081  {
12082  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",MTBFEditBoxClick");
12083  LengthConversionPanel->Visible = false;
12084  SpeedConversionPanel->Visible = false;
12085  DistanceKey->Visible = false;
12086  TrackElementPanel->Visible = false;
12087  SigAspectButton->Enabled = false;
12089  SetLevel2TrackMode(63);
12090  Display->Update();
12091  if(SelectedGraphicFileName != "")
12092  {
12093  UserGraphicReselectPanel->Visible = true;
12094  }
12095  else
12096  {
12097  UserGraphicReselectPanel->Visible = false;
12098  LoadUserGraphic(0);
12099  }
12100  Utilities->CallLogPop(2183);
12101  }
12102  catch(const Exception &e)
12103  {
12104  ErrorLog(212, e.Message);
12105  }
12106 }
12107 
12108 // ---------------------------------------------------------------------------
12109 
12110 void __fastcall TInterface::ReselectUserGraphicClick(TObject *Sender)
12111 {
12112  try
12113  {
12114  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ReselectUserGraphicClick");
12115  TrainController->LogEvent("ReselectUserGraphicClick " + SelectedGraphicFileName);
12116  UserGraphicReselectPanel->Visible = false;
12117  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
12118  if(UGMIt == Track->UserGraphicMap.end())
12119  {
12120  ShowMessage("Unable to find graphic file " + SelectedGraphicFileName + ". Check it still exists.");
12121  Utilities->CallLogPop(2196);
12122  return;
12123  }
12125  SetLevel2TrackMode(64);
12126  Utilities->CallLogPop(2184);
12127  }
12128  catch(const Exception &e)
12129  {
12130  ErrorLog(213, e.Message);
12131  }
12132 }
12133 // ---------------------------------------------------------------------------
12134 
12135 void __fastcall TInterface::SelectNewGraphicClick(TObject *Sender)
12136 {
12137  try
12138  {
12139  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",SelectNewGraphicClick");
12140  UserGraphicReselectPanel->Visible = false;
12141  LoadUserGraphic(1);
12142  Utilities->CallLogPop(2185);
12143  }
12144  catch(const Exception &e)
12145  {
12146  ErrorLog(214, e.Message);
12147  }
12148 }
12149 
12150 // ---------------------------------------------------------------------------
12151 
12152 void __fastcall TInterface::TTClockAdjustOKButtonClick(TObject *Sender)
12153 {
12154  try
12155  {
12156  TrainController->LogEvent("TTClockAdjustOKButtonClick");
12157  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",TTClockAdjustOKButtonClick");
12158  TTClockAdjustWarningPanel->Visible = false;
12159  if(TTClockAdjustCheckBox->Checked)
12160  {
12161  TTClockAdjustWarningHide = true;
12162  }
12163  Utilities->CallLogPop(2219);
12164  }
12165  catch(const Exception &e)
12166  {
12167  ErrorLog(216, e.Message);
12168  }
12169 }
12170 
12171 //---------------------------------------------------------------------------
12172 
12173 void __fastcall TInterface::ConflictAnalysisButtonClick(TObject *Sender)
12174 {
12175  try
12176  {
12177  TrainController->LogEvent("ConflictAnalysisButtonClick");
12178  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",ConflictAnalysisButtonClick");
12179  ConflictPanel->Visible = true;
12180  Utilities->CallLogPop(2220);
12181  }
12182  catch(const Exception &e)
12183  {
12184  ErrorLog(217, e.Message);
12185  }
12186 }
12187 
12188 //---------------------------------------------------------------------------
12189 
12190 void __fastcall TInterface::CPCancelButtonClick(TObject *Sender)
12191 {
12192  try
12193  {
12194  TrainController->LogEvent("CPCancelButtonClick");
12195  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPCancelButtonClick");
12196  ConflictPanel->Visible = false;
12197  Utilities->CallLogPop(2221);
12198  }
12199  catch(const Exception &e)
12200  {
12201  ErrorLog(218, e.Message);
12202  }
12203 }
12204 
12205 //---------------------------------------------------------------------------
12206 
12207 void __fastcall TInterface::CPGenFileButtonClick(TObject *Sender)
12208 {
12209  try
12210  {
12211  TrainController->LogEvent("CPGenFileButtonClick");
12212  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",CPGenFileButtonClick");
12213  if(!CPArrivalsCheckBox->Checked && !CPDeparturesCheckBox->Checked && !CPAtLocCheckBox->Checked)
12214  {
12215  ShowMessage("No boxes ticked!");
12216  }
12217  else //keep ticks & range values from last time, only reset on startup
12218  {
12219  Screen->Cursor = TCursor(-11);//hourglass
12220  AnsiString TTTitle;
12222  {
12223  for(int x = CreateEditTTFileName.Length(); x > 0; x--) // first need to strip out the timetable title from the full name
12224  {
12225  if(CreateEditTTFileName[x] == '\\')
12226  {
12227  TTTitle = CreateEditTTFileName.SubString(x + 1, CreateEditTTFileName.Length() - x - 4);
12228  break;
12229  }
12230  }
12232  CPAtLocCheckBox->Checked, CPEditArrRange->Text.ToInt(), CPEditDepRange->Text.ToInt()))
12233  {
12234  ShowMessage("Analysis complete and file created");
12235  }
12236  ConflictPanel->Visible = false;
12237  }
12238  }
12239  Screen->Cursor = TCursor(-2);//arrow
12240  Utilities->CallLogPop(2222);
12241  }
12242  catch(const Exception &e)
12243  {
12244  ErrorLog(219, e.Message);
12245  }
12246 }
12247 
12248 //---------------------------------------------------------------------------
12249 // end of fastcalls & directly associated functions
12250 // ---------------------------------------------------------------------------
12251 
12252 void TInterface::SetTopIndex(int Caller)
12253 {
12254 //Set TopIndex to the proper value & also Selected so don't have a different selection to the highlighted entry
12255  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTopIndex");
12256  if((TTCurrentEntryPtr - TimetableEditVector.begin()) < AllEntriesTTListBox->TopIndex)
12257  {
12259  }
12260  else if((TTCurrentEntryPtr - TimetableEditVector.begin()) > (AllEntriesTTListBox->TopIndex + 45))
12261  {
12262  AllEntriesTTListBox->TopIndex = TTCurrentEntryPtr - TimetableEditVector.begin() - 45;
12263  }
12264  else
12265  {
12266  AllEntriesTTListBox->TopIndex = AllEntriesTTListBox->TopIndex;
12267  }
12268  AllEntriesTTListBox->Selected[TTCurrentEntryPtr - TimetableEditVector.begin()] = true;
12269  Utilities->CallLogPop(2207);
12270 }
12271 
12272 // ---------------------------------------------------------------------------
12273 
12274 void TInterface::ClearandRebuildRailway(int Caller) // now uses HiddenScreen to help avoid flicker
12275 {
12276  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearandRebuildRailway");
12277  bool ClockState = Utilities->Clock2Stopped;
12278 
12279  Utilities->Clock2Stopped = true;
12281  Track->RebuildUserGraphics(0, HiddenDisplay); // new at v2.4.0, plot first so all else overwrites, including the grid if selected
12282  if(ScreenGridFlag && (Level1Mode == TrackMode))
12283  {
12284  int WidthNum = int(MainScreen->Width / 160) + 1;
12285  int HeightNum = int(MainScreen->Height / 144) + 1;
12286  for(int x = 0; x < WidthNum; x++)
12287  {
12288  for(int y = 0; y < HeightNum; y++)
12289  {
12290  HiddenDisplay->PlotAbsolute(0, x * 160, y * 144, RailGraphics->GridBitmap);
12291  }
12292  }
12293  }
12294 
12295 // TextHandler->RebuildFromTextVector(1, HiddenDisplay); //This now incorporated in RebuildTrackAndText so that text is plotted after inactive
12296 // elements but before active elements. This is so text can overwite stations and non-station named locations.
12297 
12299 
12300 // Display->Output->Invalidate(); experiment, needs TDisplay Output to be public. Trying to invoke the white flashes that
12301 // used to occur frequently without Disp->Update() in PlotOriginal
12302 
12303  // OperMode LCs plotted below
12305  {
12307  }
12308 
12309  if(Level1Mode == PrefDirMode)
12310  {
12311  if(EveryPrefDir->PrefDirSize() > 0)
12312  {
12314  }
12316  {
12318  }
12319  }
12320 
12321  if(Level1Mode == TrackMode)
12322  {
12324  {
12325  LocationNameButton->Enabled = true;
12326  }
12327  else
12328  {
12329  LocationNameButton->Enabled = false;
12330  }
12331  }
12332 
12334  {
12336  DistanceKey->Visible = true;
12337  DistancesMarked = true;
12338  LengthConversionPanel->Visible = true;
12339  SpeedConversionPanel->Visible = true;
12340  }
12341 
12342  if(Level2TrackMode == DistanceContinuing) // for extended distances
12343  {
12344  if(ConstructPrefDir->PrefDirSize() > 0)
12345  {
12348  DistanceKey->Visible = true;
12349  DistancesMarked = true;
12350  LengthConversionPanel->Visible = true;
12351  SpeedConversionPanel->Visible = true;
12352  }
12353  }
12354 
12356  // this is to keep the distance markers if they are already present when Select is chosen, in case user wishes to choose SelectLengths,
12357  // don't need to display ConstructPrefDir marker as that only needed in DistanceContinuing mode
12358  {
12360  DistanceKey->Visible = true;
12361  }
12362 
12364  // cancel DistancesMarked if exit from any of these modes
12365  {
12366  DistancesMarked = false;
12367  DistanceKey->Visible = false;
12368  LengthConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
12369  SpeedConversionPanel->Visible = false; // added at v1.3.1 to remove when distance/speed setting exited
12370  }
12371 
12373  // in process of moving so use NewSelectBitmapHLoc & VLoc
12374  {
12376  }
12377 
12379  // not in process of moving or failed to click mouse within selection so use SelectBitmapHLoc & VLoc
12380  {
12382  }
12383 
12384  if(Level1Mode == OperMode)
12385  {
12387  if(!AllRoutes->LockedRouteVector.empty())
12388  {
12389  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
12390  {
12391  if(!(AllRoutes->TrackIsInARoute(7, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos)))
12392  {
12393  AllRoutes->LockedRouteVector.erase(LRVIT);
12394  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
12395  // hence no longer needed so get rid of it (end of route can't be points, crossover or bridge so danger of
12396  // route being on the other track of a 2-track element doesn't arise)
12397  continue;
12398  }
12399  TOneRoute Route = AllRoutes->GetFixedRouteAt(0, LRVIT->RouteNumber);
12400  int x = Route.PrefDirSize() - 1;
12401  bool BreakFlag = false;
12402  TPrefDirElement PrefDirElement = Route.GetFixedPrefDirElementAt(1, x);
12403  while(PrefDirElement.GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
12404  {
12405  HiddenDisplay->PlotOutput(10, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
12406  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
12407  if(!(AllRoutes->TrackIsInARoute(8, PrefDirElement.Conn[PrefDirElement.GetELinkPos()],
12408  PrefDirElement.ConnLinkPos[PrefDirElement.GetELinkPos()])))
12409  {
12410  BreakFlag = true;
12411  break; // train removed earlier element from route so stop here
12412  }
12413  x--;
12414  if(x < 0) //added after Albie Vowles reported error on 14/08/20 by email
12415  { //it means that part of the route (including that at the truncate point) has been cancelled, in this case by a train running past the signal
12416  BreakFlag = true; //at danger and cancelling the route elements in front of it. The locked route is now too short and this 'while' loop won't find
12417  break; //it, so x keeps decrementing and when it becomes -1 an error is thrown. This addition prevents the error.
12418  }
12419  PrefDirElement = Route.GetFixedPrefDirElementAt(2, x);
12420  }
12421  if(!BreakFlag)
12422  {
12423  if(PrefDirElement.GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
12424  {
12425  HiddenDisplay->PlotOutput(11, (PrefDirElement.HLoc) * 16, (PrefDirElement.VLoc) * 16,
12426  RailGraphics->LockedRouteCancelPtr[PrefDirElement.GetELink()]);
12427  }
12428  }
12429  }
12430  }
12431 
12432  if(RouteMode == RouteContinuing)
12433  {
12435 // system thinks overlay is already plotted, so plot original to reset the OverlayPlotted flag
12438  if(AutoSigsFlag)
12440  else if(ConsecSignalsRoute)
12442  else
12444  }
12445 
12446  if(Track->PointFlashFlag)
12447  {
12448  // need to reset the screen location for picking up the original graphic
12449  int Left, Top; // Embarcadero change - these missing in error from Borland file
12451  // note that the above Pos values are wrt layout, not the screen, but the Left & Top values are wrt screen
12452  PointFlash->SetSourceRect(Left, Top);
12453  PointFlash->LoadOriginalScreenGraphic(4); // reload from new position
12454  // doesn't matter whether Flash was on or off when this function called as will sort itself out later (may miss a flash but won't be noticeable)
12455  }
12456 
12457  // now plot level crossings (must be after routes). These don't need any base elements to be plotted as they are already plotted.
12458  // In order to avoid plotting the whole LC for every element of a LC a TempMarker is used
12459  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
12460  {
12461  (Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)))->TempMarker = false;
12462  }
12463  for(unsigned int x = 0; x < Track->LCVector.size(); x++)
12464  {
12465  int BaseSpeedTag;
12466  TTrackElement ATE;
12467  TTrackElement ITE = *(Track->InactiveTrackVector.begin() + (*(Track->LCVector.begin() + x)));
12468  {
12469  BaseSpeedTag = Track->GetTrackElementFromTrackMap(0, ITE.HLoc, ITE.VLoc).SpeedTag;
12470  if(ITE.TempMarker == false)
12471  {
12472  if(ITE.Attribute == 0)
12473  {
12475  }
12476  else if(ITE.Attribute == 1)
12477  {
12479  }
12480  // if ITE->Attribute == 2 then LC is changing, FlashingGraphics will take care of flashing & final plotting
12481  // won't set marker but no real time lost in this case
12482  }
12483  }}
12485  }
12486 
12487  Display->ZoomOutFlag = false;
12488  ZoomButton->Glyph->LoadFromResourceName(0, "ZoomOut");
12489  MainScreen->Picture->Bitmap->Assign(HiddenScreen->Picture->Bitmap);
12490  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
12491  Utilities->Clock2Stopped = ClockState;
12492  Utilities->CallLogPop(91);
12493 }
12494 
12495 // ---------------------------------------------------------------------------
12496 
12497 bool TInterface::HighLightOneGap(int Caller, int &HLoc, int &VLoc)
12498 {
12499  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",HighLightOneGap");
12500  if(Track->FindAndHighlightAnUnsetGap(1)) // true if find one
12501  {
12502  if(!PreventGapOffsetResetting) // don't reset display position if returning from zoomout mode
12503  {
12504  while((Display->DisplayOffsetH - Track->GetGapHLoc()) > 0)
12505  Display->DisplayOffsetH -= (Utilities->ScreenElementWidth / 2); // use 30 instead of 60 so less likely to appear behind the message box
12508  while((Display->DisplayOffsetV - Track->GetGapVLoc()) > 0)
12509  Display->DisplayOffsetV -= (Utilities->ScreenElementHeight / 2); // use 18 instead of 36 so less likely to appear behind the message box
12512  }
12513  InfoPanel->Visible = true;
12514  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting element";
12515  ClearandRebuildRailway(31); // get rid of earlier gap selection
12516  Utilities->CallLogPop(92);
12517  return true; // return as one now identified & over to MainScreenMouseDown with Level2TrackMode = GapSetting
12518  }
12519  Utilities->CallLogPop(93);
12520  return false; // no unset ones left to find
12521 }
12522 
12523 // ---------------------------------------------------------------------------
12524 
12526 {
12527  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearEverything");
12528  if(FileChangedFlag)
12529  {
12530  UnicodeString MessageStr = "The railway has changed, close it without saving?";
12531  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
12532  if(button == IDNO)
12533  {
12534  Utilities->CallLogPop(1140);
12535  return false;
12536  }
12537  }
12538  Display->ClearDisplay(7);
12540 
12541  Display->DisplayOffsetH = 0;
12542  Display->DisplayOffsetV = 0;
12547 
12548 // these ensure that all persistent vectors, maps & multimaps etc are cleared
12549  delete TrainController;
12550  delete EveryPrefDir;
12551  delete ConstructRoute;
12552  delete ConstructPrefDir;
12553  delete AllRoutes;
12554  delete Track;
12555  delete TextHandler;
12556 // NB can't delete & recreate Utilities or will lose the CallLog file & have errors due to log being empty when try to
12557 // pop earlier pushed values
12558 // OK though as no containers in Utilities that need to clear & PerformanceFile recreated when begin to operate a later
12559 // railway
12560  TextHandler = new TTextHandler;
12561  Track = new TTrack;
12562  AllRoutes = new TAllRoutes;
12564  ConstructRoute = new TOneRoute;
12565  EveryPrefDir = new TOnePrefDir;
12567  PerformanceLogBox->Lines->Clear();
12568  ResetAll(1);
12569  Utilities->CallLogPop(94);
12570  return true;
12571 }
12572 
12573 // ---------------------------------------------------------------------------
12574 
12575 bool TInterface::FileIntegrityCheck(int Caller, char *FileName) const // true for success
12576 {
12577  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FileIntegrityCheck," + AnsiString(FileName));
12578  std::ifstream VecFile(FileName);
12579 
12580  if(VecFile.is_open())
12581  {
12582  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // Program version
12583  {
12584  VecFile.close();
12585  Utilities->CallLogPop(1805);
12586  return false;
12587  }
12588  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetHHome
12589  {
12590  VecFile.close();
12591  Utilities->CallLogPop(1440);
12592  return false;
12593  }
12594  if(!Utilities->CheckFileInt(VecFile, -1000000, 1000000)) // DisplayOffsetVHome
12595  {
12596  VecFile.close();
12597  Utilities->CallLogPop(1441);
12598  return false;
12599  }
12600  bool GraphicsFollow = false;
12601  int NumberOfActiveElements;
12602  if(!(Track->CheckTrackElementsInFile(1, NumberOfActiveElements, GraphicsFollow, VecFile))) // for new loads
12603  {
12604  VecFile.close();
12605  Utilities->CallLogPop(95);
12606  return false;
12607  }
12608  if(!(TextHandler->CheckTextElementsInFile(0, VecFile)))
12609  {
12610  VecFile.close();
12611  Utilities->CallLogPop(96);
12612  return false;
12613  }
12614  if(!(EveryPrefDir->CheckOnePrefDir(0, NumberOfActiveElements, VecFile)))
12615  {
12616  VecFile.close();
12617  Utilities->CallLogPop(97);
12618  return false;
12619  }
12620  if(GraphicsFollow)
12621  {
12622  if(!Track->CheckUserGraphics(0, VecFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
12623  {
12624  VecFile.close();
12625  Utilities->CallLogPop(2186);
12626  return false;
12627  }
12628  }
12629  VecFile.close();
12630  }
12631  else
12632  {
12633  Utilities->CallLogPop(1153);
12634  return false;
12635  }
12636  Utilities->CallLogPop(98);
12637  return true;
12638 }
12639 
12640 // ---------------------------------------------------------------------------
12641 
12642 void TInterface::Delay(int Caller, double Msec)
12643 {
12644  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Delay," + AnsiString(Msec));
12645  TDateTime First, Second;
12646  bool Finished = false;
12647 
12648  First = TDateTime::CurrentDateTime();
12649  double TimeVal1 = 86400000 * double(First); // no of msec in a day
12650 
12651  while(!Finished)
12652  {
12653  Second = TDateTime::CurrentDateTime();
12654  double TimeVal2 = 86400000 * double(Second);
12655  if((TimeVal2 - TimeVal1) > Msec)
12656  Finished = true;
12657  }
12658  Utilities->CallLogPop(1203);
12659 }
12660 
12661 // ---------------------------------------------------------------------------
12662 
12664 {
12665  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetCurrentSpeedButton");
12666  if(CurrentSpeedButton)
12667  CurrentSpeedButton->Down = false;
12668  CurrentSpeedButton = 0;
12669  Utilities->CallLogPop(1204);
12670 }
12671 
12672 // ---------------------------------------------------------------------------
12673 
12675 {
12676  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MovingTrainPresentOnFlashingRoute");
12677  int TrainID;
12678 
12679  if(ConstructRoute->SearchVectorSize() == 0)
12680  {
12681  Utilities->CallLogPop(99);
12682  return false;
12683  }
12684  for(unsigned int x = 0; x < ConstructRoute->SearchVectorSize(); x++)
12685  {
12686  TPrefDirElement PrefDirElement = ConstructRoute->GetFixedSearchElementAt(14, x);
12687  if(PrefDirElement.TrackType == Bridge)
12688  {
12689  if(PrefDirElement.GetXLinkPos() < 2)
12690  TrainID = Track->TrackElementAt(486, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos01;
12691  else
12692  TrainID = Track->TrackElementAt(487, PrefDirElement.GetTrackVectorPosition()).TrainIDOnBridgeTrackPos23;
12693  }
12694  else
12695  TrainID = Track->TrackElementAt(488, PrefDirElement.GetTrackVectorPosition()).TrainIDOnElement;
12696  if((TrainID > -1) && !(TrainController->TrainVectorAtIdent(4, TrainID).Stopped()))
12697  {
12698  Utilities->CallLogPop(100);
12699  return true;
12700  }
12701  // check for crossed diagonal fouling by train added at v1.2.0
12702  int TrainID; // not used
12703  int LinkNumber1 = PrefDirElement.Link[PrefDirElement.GetELinkPos()];
12704  int LinkNumber2 = PrefDirElement.Link[PrefDirElement.GetXLinkPos()];
12705  if((LinkNumber1 == 1) || (LinkNumber1 == 3) || (LinkNumber1 == 7) || (LinkNumber1 == 9))
12706  {
12707  if(Track->DiagonalFouledByTrain(1, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber1, TrainID))
12708  {
12709  Utilities->CallLogPop(2037);
12710  return true;
12711  }
12712  }
12713  if((LinkNumber2 == 1) || (LinkNumber2 == 3) || (LinkNumber2 == 7) || (LinkNumber2 == 9))
12714  {
12715  if(Track->DiagonalFouledByTrain(2, PrefDirElement.HLoc, PrefDirElement.VLoc, LinkNumber2, TrainID))
12716  {
12717  Utilities->CallLogPop(2038);
12718  return true;
12719  }
12720  }
12721  }
12722  Utilities->CallLogPop(101);
12723  return false;
12724 }
12725 
12726 // ---------------------------------------------------------------------------
12727 
12729 {
12730  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RevertToOriginalRouteSelector");
12731  AutoRouteStartMarker->PlotOriginal(26, Display); // if overlay not plotted will ignore
12732  SigRouteStartMarker->PlotOriginal(27, Display); // if overlay not plotted will ignore
12733  NonSigRouteStartMarker->PlotOriginal(28, Display); // if overlay not plotted will ignore
12734  RouteCancelFlag = false;
12736  {
12737  RouteCancelButton->Enabled = true;
12738  }
12739  else
12740  {
12741  RouteCancelButton->Enabled = false;
12742  }
12745 // reset here so that a n element that has been selected and then not doesn't remain set as a single element
12746  InfoPanel->Visible = true;
12747  if(Level2OperMode != Paused)
12748  {
12749  InfoPanel->Caption = InfoCaptionStore;
12750  }
12751  Utilities->CallLogPop(102);
12752 }
12753 
12754 // ---------------------------------------------------------------------------
12755 
12756 // usermode functions below
12758 {
12759  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel1Mode");
12760  if(!Display->ZoomOutFlag)
12761  {
12764  Track->GapFlashFlag = false;
12765  }
12766 // GapFlash resets when any mode selected unless zoomed out
12767 // note that if selecting zoom back in then this will be called before ZoomOutFlag is reset so won't
12768 // reset GapFlashFlag
12769  switch(Level1Mode) // use the data member
12770  {
12771  case BaseMode:
12772  CopyMenuItem->ShortCut = TextToShortCut(""); // added these for v2.1.0 to set default values after use of the 'Edit' menu during track building
12773  CutMenuItem->ShortCut = TextToShortCut(""); // to allow normal cutting/copying/pasting, especially in timetable construction or editing
12774  PasteMenuItem->ShortCut = TextToShortCut("");
12779  LengthConversionPanel->Visible = false;
12780  SpeedConversionPanel->Visible = false;
12781  TimetableEditPanel->Visible = false;
12782  TrackBuildPanel->Visible = false;
12783  TrackElementPanel->Visible = false;
12784  LocationNameTextBox->Visible = false;
12785  TextBox->Visible = false;
12786  TrackLengthPanel->Visible = false;
12787  InfoPanel->Visible = false;
12788  PrefDirPanel->Visible = false;
12789  TimetablePanel->Visible = false;
12790  OperatingPanel->Visible = false;
12791  PrefDirKey->Visible = false;
12792  TrackLinkedImage->Visible = false;
12793  TrackNotLinkedImage->Visible = false;
12794  GapsSetImage->Visible = false;
12795  GapsNotSetImage->Visible = false;
12796  LocationNamesSetImage->Visible = false;
12797  LocationNamesNotSetImage->Visible = false;
12798  ModeMenu->Enabled = true;
12799  FileMenu->Enabled = true;
12800  EditMenu->Enabled = false;
12801  BuildTrackMenuItem->Enabled = true;
12802  SigAspectButton->Enabled = false;
12803  Track->ChangingLCVector.clear();
12804  Track->BarriersDownVector.clear();
12806  ConverttoRightHandSignalsMenuItem->Enabled = false; // new at v2.3.0
12807  SigImagePanel->Visible = false; // new at v2.3.0
12808  MTBFEditBox->Visible = false; // new at v2.4.0
12809  MTBFLabel->Visible = false;
12810  TTClockAdjustWarningPanel->Visible = false;
12811  if(Track->IsTrackFinished())
12812  {
12813  PlanPrefDirsMenuItem->Enabled = true;
12814  if(TimetableTitle != "")
12815  {
12816  OperateRailwayMenuItem->Enabled = true;
12817  }
12818  else
12819  {
12820  OperateRailwayMenuItem->Enabled = false;
12821  }
12822  }
12823  else
12824  {
12825  PlanPrefDirsMenuItem->Enabled = false;
12826  OperateRailwayMenuItem->Enabled = false;
12827  }
12828  if(RlyFile)
12829  {
12830  LoadTimetableMenuItem->Enabled = true;
12831  }
12832  else
12833  {
12834  LoadTimetableMenuItem->Enabled = false;
12835  }
12836  LoadRailwayMenuItem->Enabled = true;
12837  if(NoRailway())
12838  {
12839  SaveAsMenuItem->Enabled = false;
12840  ImageMenu->Enabled = false;
12841  SaveImageAndGridMenuItem->Enabled = false;
12842  SaveImageNoGridMenuItem->Enabled = false;
12843  SaveImageAndPrefDirsMenuItem->Enabled = false;
12844  SaveOperatingImageMenuItem->Enabled = false;
12845  BlackBgndMenuItem->Enabled = false;
12846  WhiteBgndMenuItem->Enabled = false;
12847  BlueBgndMenuItem->Enabled = false;
12848  ConverttoRightHandSignalsMenuItem->Enabled = true; // new at v2.3.0
12849  SigImagePanel->Visible = true; // new at v2.3.0
12850  if(Utilities->clTransparent != TColor(0))
12851  {
12852  BlackBgndMenuItem->Enabled = true;
12853  }
12854  if(Utilities->clTransparent != TColor(0xFFFFFF))
12855  {
12856  WhiteBgndMenuItem->Enabled = true;
12857  }
12858  if(Utilities->clTransparent != TColor(0x330000))
12859  {
12860  BlueBgndMenuItem->Enabled = true;
12861  }
12862  ClearAllMenuItem->Enabled = false;
12863  InfoPanel->Visible = true;
12864  InfoPanel->Caption = "Select an option from the File, Mode or Help menus";
12865  }
12866  else
12867  {
12868  InfoPanel->Visible = false;
12869  SaveAsMenuItem->Enabled = true;
12870  ImageMenu->Enabled = true;
12871  SaveImageAndGridMenuItem->Enabled = true;
12872  SaveImageNoGridMenuItem->Enabled = true;
12873  if(EveryPrefDir->PrefDirSize() > 0)
12874  SaveImageAndPrefDirsMenuItem->Enabled = true;
12875  else
12876  SaveImageAndPrefDirsMenuItem->Enabled = false;
12877  BlackBgndMenuItem->Enabled = false;
12878  WhiteBgndMenuItem->Enabled = false;
12879  BlueBgndMenuItem->Enabled = false;
12880  SaveOperatingImageMenuItem->Enabled = false;
12881  ClearAllMenuItem->Enabled = true;
12882  }
12883  if(SavedFileName == "")
12884  {
12885  SaveMenuItem->Enabled = false;
12886  }
12887  else if(!FileChangedFlag)
12888  {
12889  SaveMenuItem->Enabled = false;
12890  }
12891  else if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
12892  {
12893  if(!(Track->IsReadyForOperation()))
12894  {
12895  SaveMenuItem->Enabled = false; // can't save under its old name as not now a .rly file
12896  }
12897  else
12898  {
12899  SaveMenuItem->Enabled = true; // must have changed some of the PrefDirs (because FileChangedFlag is true)
12900  }
12901  }
12902  else
12903  SaveMenuItem->Enabled = true;
12904  LoadSessionMenuItem->Enabled = true;
12905  ExitMenuItem->Enabled = true;
12906  ScreenGridFlag = false;
12907  TrainController->CrashWarning = false;
12908  TrainController->DerailWarning = false;
12909  TrainController->SPADWarning = false;
12911  TrainController->CallOnWarning = false;
12914  UserGraphicReselectPanel->Visible = false;
12915  ClearandRebuildRailway(32); // to get rid of unwanted displays (eg distance markers)
12916  SetTrackBuildImages(13);
12917  break;
12918 
12919  case TimetableMode:
12923  ModeMenu->Enabled = false;
12924  SigImagePanel->Visible = false; // new at v2.3.0
12925  FileMenu->Enabled = false;
12926  EditMenu->Enabled = false;
12927  FloatingInfoMenu->Enabled = false;
12928  ImageMenu->Enabled = false;
12929  TimetableEditPanel->BringToFront();
12930  TimetableHandler();
12931  break;
12932 
12933  case TrackMode:
12934  if(Level2TrackMode == CutMoving)
12935  {
12936  Level2TrackMode = Pasting; // paste the selection
12937  SetLevel2TrackMode(52);
12938  }
12943  TrackBuildPanel->Visible = true;
12944  TrackBuildPanelLabel->Caption = "Build/modify";
12945  TrackElementPanel->Visible = false;
12946  TrackLengthPanel->Visible = false;
12947  PrefDirPanel->Visible = false;
12948  TimetablePanel->Visible = false;
12949  OperatingPanel->Visible = false;
12950  InfoPanel->Visible = false;
12951  InfoPanel->Caption = "";
12952  LocationNameTextBox->Visible = false;
12953  TextBox->Visible = false;
12954  ModeMenu->Enabled = false;
12955  SigImagePanel->Visible = false; // new at v2.3.0
12956  FileMenu->Enabled = false;
12957  // set edit menu items
12959  // track buttons
12960  AddTrackButton->Enabled = true;
12962  {
12963  LocationNameButton->Enabled = true;
12964  }
12965  else
12966  {
12967  LocationNameButton->Enabled = false;
12968  }
12969  ScreenGridButton->Enabled = true;
12970  ExitTrackButton->Enabled = true;
12971  SetGapsButton->Enabled = false;
12972  TrackOKButton->Enabled = false;
12973  if(Track->GapsUnset(5))
12974  {
12975  SetGapsButton->Enabled = true;
12976  }
12977  // only enable if there are gaps still to be set (returns false for no track)
12978  else
12979  {
12980  if(!(Track->NoActiveTrack(2)) && !(Track->IsTrackFinished()))
12981  {
12982  TrackOKButton->Enabled = true;
12983  }
12984  // TrackOK only enabled if track exists, there are no unset gaps, and track not finished
12985  }
12986  SetLengthsButton->Enabled = false;
12987  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
12988  {
12989  SetLengthsButton->Enabled = true;
12990  }
12991  // text buttons
12992  AddTextButton->Enabled = true;
12993  TextOrUserGraphicGridButton->Enabled = true;
12994  FontButton->Enabled = true;
12995  MoveTextOrGraphicButton->Enabled = false;
12996  if(TextHandler->TextVectorSize(9) > 0)
12997  {
12998  MoveTextOrGraphicButton->Enabled = true;
12999  }
13000  if(!Track->UserGraphicVector.empty())
13001  {
13002  MoveTextOrGraphicButton->Enabled = true;
13003  }
13004  SelectionValid = false;
13006  TimetableTitle = "";
13007  SetCaption(0);
13008  break;
13009 
13010  case PrefDirMode:
13014  PrefDirPanel->Visible = true;
13015  PrefDirPanelLabel->Caption = "Preferred direction selection";
13016 
13017  InfoPanel->Visible = true;
13018  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select preferred direction start location (right click to erase)";
13019  PrefDirKey->Visible = true;
13020  ModeMenu->Enabled = false;
13021  SigImagePanel->Visible = false; // new at v2.3.0
13022  FileMenu->Enabled = false;
13023 // set edit menu items
13025  AddPrefDirButton->Enabled = false;
13026  DeleteOnePrefDirButton->Enabled = false;
13028  if(EveryPrefDir->PrefDirSize() > 0)
13029  {
13030  DeleteAllPrefDirButton->Visible = true;
13031  DeleteAllPrefDirButton->Enabled = true;
13032  SaveImageAndPrefDirsMenuItem->Enabled = true;
13033  }
13034  else
13035  {
13036  DeleteAllPrefDirButton->Enabled = false;
13037  SaveImageAndPrefDirsMenuItem->Enabled = false;
13038  }
13039  ExitPrefDirButton->Enabled = true;
13040  ClearandRebuildRailway(33); // to mark PrefDirs & clear earlier PrefDir markers
13041 // TimetableTitle = ""; no need to unload timetable if only PrefDirs being changed
13042 // SetCaption();
13043  break;
13044 
13045  case OperMode: // if there are any PrefDirs, set to SigPref, else to NoSigNonPref; start in Paused mode
13049  OperatingPanel->Visible = true;
13050  OperatingPanelLabel->Caption = "Operation";
13051 
13052  CallingOnButton->Visible = false;
13053  PresetAutoSigRoutesButton->Visible = true;
13054  PresetAutoSigRoutesButton->Enabled = true;
13055  InfoPanel->Visible = true;
13056  SigImagePanel->Visible = false; // new at v2.3.0
13057  ModeMenu->Enabled = false;
13058  FileMenu->Enabled = false;
13059  EditMenu->Enabled = false;
13060  ImageMenu->Enabled = true;
13061  SaveImageAndGridMenuItem->Enabled = true;
13062  SaveImageNoGridMenuItem->Enabled = true;
13063  if(EveryPrefDir->PrefDirSize() > 0)
13064  SaveImageAndPrefDirsMenuItem->Enabled = true;
13065  else
13066  SaveImageAndPrefDirsMenuItem->Enabled = false;
13067  SaveOperatingImageMenuItem->Enabled = true;
13068  AutoSigsFlag = false;
13069  MTBFEditBox->Visible = true; // visible at pre-start whether any value set or not, so can set a value if required
13071  {
13072  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
13073  }
13074  else
13075  {
13076  MTBFEditBox->Text = "";
13077  }
13078  MTBFEditBox->ReadOnly = false; // because this is prestart mode
13079  MTBFLabel->Visible = true;
13080  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13082  if(EveryPrefDir->PrefDirSize() > 0)
13083  {
13084  ConsecSignalsRoute = true;
13085  PreferredRoute = true;
13086  }
13087  else // no PrefDirs
13088  {
13089  ConsecSignalsRoute = false;
13090  PreferredRoute = false;
13091  }
13092 
13093  OperateButton->Enabled = true;
13094  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
13095  ExitOperationButton->Enabled = true;
13096  TTClockAdjButton->Enabled = true;
13097  ShowPerformancePanel = false;
13098  PerformanceLogButton->Glyph->LoadFromResourceName(0, "ShowLog");
13099  ShowOperatorActionPanel = false; // new at v2.2.0
13100  OperatorActionButton->Glyph->LoadFromResourceName(0, "ShowOpActionPanel"); // new v2.2.0
13101 
13103 
13104  Utilities->Clock2Stopped = false;
13108  TTClockSpeed = 1;
13109  TTClockSpeedLabel->Caption = "x1";
13111 
13112  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
13113  // format "16/06/2009 20:55:17"
13114  // avoid characters in filename:= / \ : * ? " < > |
13115  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " + TimetableTitle + ".txt";
13116 
13117  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
13118  if(Utilities->PerformanceFile.fail())
13119  {
13120  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
13121  " in the folder where the 'Railway.exe' program file resides");
13122  }
13124 // DisableRouteButtons(2); enable route setting or pre-start
13125 // DisablePanelsStoreMainMenuStates();
13126  TrainController->ContinuationAutoSigVector.clear(); // for restarting after earlier run
13127  AllRoutes->LockedRouteVector.clear(); // for restarting after earlier run
13128 // TrainController->Operate(1);//plot trains that are present at TT start time, ready for running - no, allow route plotting prior to train entries
13129 
13130 // reset all performance indicators
13154 
13155  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
13156  OAListBox->Clear();
13157  OAListBox->Items->Add(L""); // hints for OpActionPanel
13158  OAListBox->Items->Add(L"");
13159  OAListBox->Items->Add(L"");
13160  OAListBox->Items->Add(L"Left click");
13161  OAListBox->Items->Add(L"headcode");
13162  OAListBox->Items->Add(L"to locate train");
13163  OAListBox->Items->Add(L"");
13164  OAListBox->Items->Add(L"");
13165  OAListBox->Items->Add(L"");
13166  OAListBox->Items->Add(L"");
13167  OAListBox->Items->Add(L"Left click and");
13168  OAListBox->Items->Add(L"hold grey area");
13169  OAListBox->Items->Add(L"to move panel");
13170 
13171  ClearandRebuildRailway(55); // so points display with one fillet
13172  break;
13173 
13174  case RestartSessionOperMode: // restart in Paused mode after a session load, sets both Level1Mode & Level2OperMode
13175  Level1Mode = OperMode;
13176 // Level2OperMode = Paused; this is now loaded during LoadInterface & could be PreStart of Paused
13179  OperatingPanel->Visible = true;
13180  OperatingPanelLabel->Caption = "Operation";
13181 
13182  CallingOnButton->Visible = true;
13183  PresetAutoSigRoutesButton->Visible = false;
13184  InfoPanel->Visible = true;
13185  ModeMenu->Enabled = false;
13186  SigImagePanel->Visible = false; // new at v2.3.0
13187  FileMenu->Enabled = false;
13188  EditMenu->Enabled = false;
13189  ImageMenu->Enabled = true;
13190  SaveImageAndGridMenuItem->Enabled = true;
13191  SaveImageNoGridMenuItem->Enabled = true;
13192  if(EveryPrefDir->PrefDirSize() > 0)
13193  SaveImageAndPrefDirsMenuItem->Enabled = true;
13194  else
13195  SaveImageAndPrefDirsMenuItem->Enabled = false;
13196  SaveOperatingImageMenuItem->Enabled = true;
13197 
13198  OperateButton->Enabled = true;
13199  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
13200  ExitOperationButton->Enabled = true;
13201  TTClockAdjButton->Enabled = true;
13204  if(Level2OperMode == Paused)
13205  DisableRouteButtons(3); // could be PreStart or Paused
13209  TTClockSpeed = 1;
13210  TTClockSpeedLabel->Caption = "x1";
13212  ShowPerformancePanel = false; // added at v2.2.0
13213  ShowOperatorActionPanel = false; // new at v2.2.0
13214  TrainController->OpActionPanelHintDelayCounter = 0; // new at v2.2.0 to reset hint delay
13215  OAListBox->Clear();
13216  OAListBox->Items->Add(L""); // hints for OpActionPanel
13217  OAListBox->Items->Add(L"");
13218  OAListBox->Items->Add(L"");
13219  OAListBox->Items->Add(L"Left click");
13220  OAListBox->Items->Add(L"headcode");
13221  OAListBox->Items->Add(L"to locate train");
13222  OAListBox->Items->Add(L"");
13223  OAListBox->Items->Add(L"");
13224  OAListBox->Items->Add(L"");
13225  OAListBox->Items->Add(L"");
13226  OAListBox->Items->Add(L"Left click and");
13227  OAListBox->Items->Add(L"hold grey area");
13228  OAListBox->Items->Add(L"to move panel");
13229  if((TrainController->AvHoursIntValue > 0) || (Level2OperMode == PreStart)) // only visible if already set or if still in prestart mode
13230  {
13231  MTBFEditBox->Visible = true;
13233  {
13234  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
13235  }
13236  else
13237  {
13238  MTBFEditBox->Text = "";
13239  }
13240  MTBFEditBox->ReadOnly = false; // because this is still prestart mode
13241  MTBFLabel->Visible = true;
13242  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13244  }
13245  else
13246  {
13247  MTBFEditBox->Visible = false;
13248  MTBFEditBox->Text = "";
13249  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
13250  MTBFLabel->Visible = false;
13251  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13253  }
13254  break;
13255 
13256  default:
13257  // No further recursion in BaseMode so OK
13258  Level1Mode = BaseMode;
13259  SetLevel1Mode(29);
13260  break;
13261  }
13262  Utilities->CallLogPop(103);
13263 }
13264 
13265 // ---------------------------------------------------------------------------
13266 
13268 {
13269  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2TrackMode");
13270  if(Level1Mode != TrackMode)
13271  {
13272  // No further recursion in BaseMode so OK
13273  Level1Mode = BaseMode;
13274  SetLevel1Mode(20);
13275  Utilities->CallLogPop(1115);
13276  return;
13277  }
13279  {
13280  Utilities->CallLogPop(104);
13281  return;
13282  }
13283  switch(Level2TrackMode) // use the data member
13284  {
13285  case AddTrack:
13287  InfoPanel->Visible = true;
13288  InfoPanel->Caption = "ADDING TRACK: Select element then left click to add it. Right click an element to remove it.";
13289  LengthConversionPanel->Visible = false; // in case had been in distance setting mode
13290  SpeedConversionPanel->Visible = false; // in case had been in distance setting mode
13291  TrackElementPanel->Visible = true;
13292  TrackElementPanel->Enabled = true;
13293  SigAspectButton->Visible = true;
13294  SigAspectButton->Enabled = true;
13295  ClearandRebuildRailway(34); // to replot grid if required & clear any other unwanted items
13297  SetLengthsButton->Enabled = false;
13298  if(Track->IsTrackFinished()) // can only set lengths for several elements together if TrackFinished
13299  {
13300  SetLengthsButton->Enabled = true;
13301  }
13302  UserGraphicReselectPanel->Visible = false;
13303  SelectLengthsFlag = false; // in case still set though probably won't be
13304  break;
13305 
13306  case AddGraphic:
13307  InfoPanel->Visible = true;
13308  InfoPanel->Caption = "ADDING GRAPHIC: Left click layout to add SELECTED graphic, right click to remove ANY graphic.";
13309  break;
13310 
13311  case SelectGraphic:
13312  InfoPanel->Visible = true;
13313  InfoPanel->Caption = "SELECTING USER GRAPHIC: Select the graphic file then add as many as necessary to the layout.";
13314  break;
13315 
13316  case GapSetting:
13317  int HLoc, VLoc, Count;
13318  Count = Track->NumberOfGaps(0);
13319  if(div(Count, 2).rem == 1) // condition OK
13320  {
13321  ShowMessage("Can't connect, there are an odd number of gaps");
13323  SetLevel1Mode(77);
13325  // No further recursion in AddTrack so OK
13326  SetLevel2TrackMode(40);
13327  Utilities->CallLogPop(105);
13328  return;
13329  }
13330  if(!HighLightOneGap(2, HLoc, VLoc)) // condition OK
13331  // need to call this here to start gap setting process off,
13332  // called in MainScreenMouseDown hereafter. Function returns false for either a LocError (links not yet
13333  // complete) or no more gaps to be highlighted
13334  {
13335  // shouldn't reach here as later gaps covered in MainScreenMouseDown but leave & give error message
13336  ShowMessage("Error - Even number of gaps but all set after first call to HighLightOneGap");
13338  SetLevel1Mode(78);
13340  // No further recursion in AddTrack so OK
13341  SetLevel2TrackMode(41);
13342  Utilities->CallLogPop(106);
13343  return; // all gaps set
13344  }
13345  InfoPanel->Visible = true;
13346  InfoPanel->Caption = "CONNECTING GAPS: Click on connecting gap";
13347  UserGraphicReselectPanel->Visible = false;
13349  break;
13350 
13351  case AddText:
13352  InfoPanel->Visible = true;
13353  InfoPanel->Caption = "ADDING/EDITING TEXT: Left click to add, right click first letter to erase, or left click first letter to edit)";
13354  if(TextHandler->TextVectorSize(13) > 0)
13355  {
13356  MoveTextOrGraphicButton->Enabled = true;
13357  }
13358  else
13359  {
13360  MoveTextOrGraphicButton->Enabled = false;
13361  }
13362  UserGraphicReselectPanel->Visible = false;
13363  ClearandRebuildRailway(58); // to drop DistanceKey if was displayed
13364  break;
13365 
13366  case MoveTextOrGraphic:
13367  InfoPanel->Visible = true;
13368  InfoPanel->Caption = "MOVING TEXT OR GRAPHIC: If text left click first letter, if graphic left click anywhere, then drag";
13369  UserGraphicReselectPanel->Visible = false;
13370  ClearandRebuildRailway(59); // to drop DistanceKey if was displayed
13371  break;
13372 
13373  case AddLocationName:
13374  InfoPanel->Visible = true;
13375  InfoPanel->Caption = "NAMING LOCATIONS: Click on location element to add or change name";
13376  ClearandRebuildRailway(35); // to get rid of earlier red rectangle
13377  UserGraphicReselectPanel->Visible = false;
13378  SetTrackBuildImages(12);
13379  break;
13380 
13381  case DistanceStart:
13382  InfoPanel->Visible = true;
13383  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select first location (only non-default elements marked)";
13384  DistanceKey->Visible = true;
13385  LengthConversionPanel->Visible = true;
13386  SpeedConversionPanel->Visible = true;
13387  UserGraphicReselectPanel->Visible = false;
13388  ClearandRebuildRailway(36); // to get rid of earlier unwanted markings
13389  break;
13390 
13391  case DistanceContinuing:
13392  InfoPanel->Visible = true;
13393  if(ConstructPrefDir->PrefDirSize() == 1)
13394  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Select next location";
13395  else
13396  InfoPanel->Caption = "DISTANCE/SPEED SETTING: Continue or set values (overall length), or right click to cancel/truncate";
13397  UserGraphicReselectPanel->Visible = false;
13398  ClearandRebuildRailway(54); // to remove earlier end marker if present
13399  break;
13400 
13401  case TrackSelecting:
13402  Track->CopyFlag = false;
13403  if(!SelectionValid)
13404  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay
13405  // the old SelectRect (only called when entered from SelectMenuItemClick, & not from
13406  // ReselectMenuItemClick)
13407  InfoPanel->Visible = true;
13408  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
13409  SelectMenuItem->Enabled = false;
13410  ReselectMenuItem->Enabled = false;
13411  CancelSelectionMenuItem->Enabled = true;
13412  UserGraphicReselectPanel->Visible = false;
13413  break;
13414 
13415  case CopyMoving:
13416  Track->CopyFlag = true;
13417  InfoPanel->Visible = true;
13418  InfoPanel->Caption = "COPYING: Left click in selection && drag";
13419  CutMenuItem->Enabled = false;
13420  CopyMenuItem->Enabled = false;
13421  FlipMenuItem->Enabled = false;
13422  MirrorMenuItem->Enabled = false;
13423  RotRightMenuItem->Enabled = false;
13424  RotLeftMenuItem->Enabled = false;
13425  RotateMenuItem->Enabled = false;
13426  PasteMenuItem->Enabled = true;
13427 // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0 - don't allow the option if copying
13428  DeleteMenuItem->Enabled = false;
13429  SelectLengthsMenuItem->Enabled = false;
13430  SelectBiDirPrefDirsMenuItem->Visible = false;
13431  CancelSelectionMenuItem->Enabled = false;
13435  UserGraphicReselectPanel->Visible = false;
13436  break;
13437 
13438  case CutMoving:
13439  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13440  // erase track elements within selected region
13441  Track->CopyFlag = false;
13442  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false; ;
13443  int ErasedTrackVectorPosition;
13444  Screen->Cursor = TCursor(-11); // Hourglass;
13445  InfoPanel->Visible = true;
13446  InfoPanel->Caption = "CUT PROCESSING: Please do not click the mouse";
13447  InfoPanel->Update();
13448  for(int H = SelectRect.left; H < SelectRect.right; H++)
13449  {
13450  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
13451  {
13452  Track->EraseTrackElement(2, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
13453  if(EraseSuccessfulFlag)
13454  {
13455  if(ErasedTrackVectorPosition > -1)
13456  EveryPrefDir->RealignAfterTrackErase(1, ErasedTrackVectorPosition);
13457  NeedToLink = true;
13458  }
13459  }
13460  }
13461  // erase text elements within selected region
13462  int LowSelectHPos = SelectRect.left * 16;
13463  int HighSelectHPos = SelectRect.right * 16;
13464  int LowSelectVPos = SelectRect.top * 16;
13465  int HighSelectVPos = SelectRect.bottom * 16;
13466  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
13467  {
13468  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
13469  TextPtr--) // reverse to prevent skipping during erase
13470  {
13471  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
13472  HighSelectVPos))
13473  {
13474  if(TextHandler->TextErase(1, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
13475  {;
13476  } // unused condition
13477  TextChangesMade = true;
13478  }
13479  }
13480  }
13481  // erase graphic elements that fall wholly within region to be overwritten
13482  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
13483  {
13484  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
13485  GraphicPtr--) // reverse to prevent skipping during erase
13486  {
13487  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
13488  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
13489  {
13490  Track->UserGraphicVector.erase(GraphicPtr);
13491  GraphicChangesMade = true;
13492  }
13493  }
13494  }
13495  Track->CheckMapAndTrack(11); // test
13496  Track->CheckMapAndInactiveTrack(10); // test
13497  Track->CheckLocationNameMultiMap(19); // test
13498  Screen->Cursor = TCursor(-2); // Arrow;
13499  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
13500  // if track not linked to begin with then becomes linked if NeedToLink false
13501  if(NeedToLink)
13502  Track->SetTrackFinished(false); // corrected for v2.1.0
13503  InfoPanel->Caption = "CUTTING: Left click in selection && drag";
13504  CutMenuItem->Enabled = false;
13505  CopyMenuItem->Enabled = false;
13506  FlipMenuItem->Enabled = false;
13507  MirrorMenuItem->Enabled = false;
13508  RotRightMenuItem->Enabled = false;
13509  RotLeftMenuItem->Enabled = false;
13510  RotateMenuItem->Enabled = false;
13511  PasteMenuItem->Enabled = true;
13512 // PasteWithAttributesMenuItem->Enabled = true; //new at v2.2.0 - option enabled if cutting
13513  DeleteMenuItem->Enabled = false;
13514  SelectLengthsMenuItem->Enabled = false;
13515  SelectBiDirPrefDirsMenuItem->Visible = false;
13516  CancelSelectionMenuItem->Enabled = false;
13519  if(NeedToLink || TextChangesMade || GraphicChangesMade)
13520  {
13521  ResetChangedFileDataAndCaption(20, true); // true for NonPrefDirChangesMade
13522  }
13523  ClearandRebuildRailway(37); // to overplot the erased elements with SelectBitmap
13524  UserGraphicReselectPanel->Visible = false;
13526  } break;
13527 
13528  case Pasting:
13529  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13532  int HDiff = SelectBitmapHLoc - SelectRect.left;
13533  int VDiff = SelectBitmapVLoc - SelectRect.top;
13534  bool NeedToLink = false;
13535  bool TrackLinkingRequiredFlag;
13536  Screen->Cursor = TCursor(-11); // Hourglass;
13537  InfoPanel->Visible = true;
13538  InfoPanel->Caption = "PASTING: Please wait";
13539  InfoPanel->Update();
13540 // erase track elements
13541  int LowSelectHLoc = SelectBitmapHLoc;
13542  int HighSelectHLoc = SelectBitmapHLoc + (SelectBitmap->Width / 16);
13543  int LowSelectVLoc = SelectBitmapVLoc;
13544  int HighSelectVLoc = SelectBitmapVLoc + (SelectBitmap->Height / 16);
13545  bool TrackEraseSuccessfulFlag; // needed but not used here
13546  int ErasedTrackVectorPosition;
13547 // new quick method of erasing, only need H & V values
13548  for(int x = LowSelectHLoc; x < HighSelectHLoc; x++)
13549  {
13550  for(int y = LowSelectVLoc; y < HighSelectVLoc; y++)
13551  {
13552  Track->EraseTrackElement(5, x, y, ErasedTrackVectorPosition, TrackEraseSuccessfulFlag, false);
13553  if(ErasedTrackVectorPosition > -1)
13554  EveryPrefDir->RealignAfterTrackErase(2, ErasedTrackVectorPosition);
13555  }
13556  }
13557 
13558 // erase text elements that fall within region to be overwritten
13559  int LowSelectHPos = SelectBitmapHLoc * 16;
13560  int HighSelectHPos = (SelectBitmapHLoc * 16) + SelectBitmap->Width;
13561  int LowSelectVPos = SelectBitmapVLoc * 16;
13562  int HighSelectVPos = (SelectBitmapVLoc * 16) + SelectBitmap->Height;
13563  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
13564  {
13565  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
13566  TextPtr--) // reverse to prevent skipping during erase
13567  {
13568  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
13569  HighSelectVPos))
13570  {
13571  if(TextHandler->TextErase(2, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
13572  {;
13573  } // unused condition
13574  }
13575  }
13576  }
13577 // erase graphic elements that fall wholly within region to be overwritten
13578  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
13579  {
13580  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
13581  GraphicPtr--) // reverse to prevent skipping during erase
13582  {
13583  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
13584  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
13585  {
13586  Track->UserGraphicVector.erase(GraphicPtr);
13587  }
13588  }
13589  }
13590  // change the H & V values in SelectVector to the new positions in case Reselect chosen
13591  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
13592  {
13593  Track->SelectVectorAt(35, x).HLoc += HDiff;
13594  Track->SelectVectorAt(1, x).VLoc += VDiff;
13595  }
13596 
13597  // add the new track elements
13598  for(unsigned int x = 0; x < Track->SelectVectorSize(); x++)
13599  {
13600  if(Track->CopyFlag) // blank all names if copying, lengths & speedlimits stay
13601  {
13602  Track->SelectVectorAt(80, x).LocationName = "";
13604  }
13605  bool InternalChecks = false;
13606 // if(Track->PastingWithAttributes) //new at v2.2.0 to select the new funtion & skip multimap checks //drop in v2.4.0
13607 // {
13609  TrackLinkingRequiredFlag, InternalChecks);
13610  // new at v2.2.0 & used in place of PlotAndAddTrackElement to keep length & speed values
13611 // }
13612 /* drop this in v2.4.0 as all pastes are past with attributes
13613  else //'Aspect' parameter added to PlotAndAdd... at v2.2.0 so can plot signals correctly (always four-aspect before)
13614  {
13615  int Aspect;
13616  if(Track->SelectVectorAt(15, x).TrackType != SignalPost) Aspect = 0; //if an '0' value appears with a SignalPost then must be adding track
13617  //this combination allows the funtion to distinguish between adding track and plotting with attributes
13618  else if(Track->SelectVectorAt(16, x).SigAspect == TTrackElement::GroundSignal) Aspect = 1;
13619  else if(Track->SelectVectorAt(17, x).SigAspect == TTrackElement::TwoAspect) Aspect = 2;
13620  else if(Track->SelectVectorAt(18, x).SigAspect == TTrackElement::ThreeAspect) Aspect = 3;
13621  else Aspect = 4;
13622  Track->PlotAndAddTrackElement(2, Track->SelectVectorAt(19, x).SpeedTag, Aspect, Track->SelectVectorAt(20, x).HLoc, Track->SelectVectorAt(21, x).VLoc, TrackLinkingRequiredFlag, InternalChecks);
13623  }
13624 */
13625  if(TrackLinkingRequiredFlag)
13626  NeedToLink = true;
13627  }
13628 
13629  if(!TextHandler->SelectTextVector.empty()) // skip iteration if empty else have an error
13630  {
13631  for(TTextHandler::TTextVectorIterator TextPtr = TextHandler->SelectTextVector.begin(); TextPtr < TextHandler->SelectTextVector.end(); TextPtr++)
13632  {
13633  TextPtr->HPos += HDiff * 16;
13634  TextPtr->VPos += VDiff * 16;
13635  AnsiString TempString = TextPtr->TextString;
13636  // have to create a new TextItem in order to create a new Font object
13637 /* drop in v2.4.0 as all pastes are paste with attributes
13638  if(!Track->PastingWithAttributes) //new at v2.2.0 to deal with the new location prefix '##**' //drop in v2.4.0
13639  {
13640  if(TextPtr->TextString.SubString(1,4) != "##**") //added for named locations so can delete in a simple paste but
13641  //use in PastingWithAttributes
13642  {
13643  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TextPtr->TextString, TextPtr->Font);
13644  TextHandler->TextVectorPush(0, TextItem); //if a normal paste include normal text but not location text
13645  }
13646  else TextPtr->TextString = ""; //delete the name for a simple paste
13647  }
13648 */
13649 // else //if pasting with attributes paste all text but strip the '##**' prefix if present
13650 // {
13651  if(TextPtr->TextString.SubString(1, 4) == "##**")
13652  {
13653  TempString = TextPtr->TextString.SubString(5, TextPtr->TextString.Length()); // don't change SelectTextVector value
13654  if(Track->CopyFlag)
13655  {
13656  TextPtr->TextString = ""; // change SelectTextVector value as reselect shouldn't have locations if copied
13657  TempString = "";
13658  }
13659  }
13660  TTextItem TextItem(TextPtr->HPos, TextPtr->VPos, TempString, TextPtr->Font);
13662 // }
13663  }
13664  }
13665  // add new graphic items
13666  if(!Track->SelectGraphicVector.empty()) // skip iteration if empty else have an error
13667  { // keep contents of SelectVector valid in case reselect
13668  for(TTrack::TUserGraphicVector::iterator GraphicPtr = Track->SelectGraphicVector.begin(); GraphicPtr < Track->SelectGraphicVector.end();
13669  GraphicPtr++)
13670  {
13671  GraphicPtr->HPos += HDiff * 16; // for reselect
13672  GraphicPtr->VPos += VDiff * 16; // for reselect
13673  Track->UserGraphicVector.push_back(*GraphicPtr);
13674  }
13675  }
13676  Track->SkipLocationNameMultiMapCheck = false; // renamed in v2.4.0 - reset the flag after pasting complete, otherwise multimap checks always skipped
13677  Track->CopyFlag = false;
13678  Track->CheckMapAndTrack(7); // test
13679  Track->CheckMapAndInactiveTrack(7); // test
13680  Track->CheckLocationNameMultiMap(7); // test
13681  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
13682  // if track not linked to begin with then becomes linked if NeedToLink false
13683  if(NeedToLink)
13684  Track->SetTrackFinished(false); // corrected for v2.1.0
13685  Screen->Cursor = TCursor(-2); // Arrow;
13686  SetTrackBuildImages(14);
13689  SetLevel1Mode(79);
13691  // No further recursion in AddTrack so OK
13692  UserGraphicReselectPanel->Visible = false;
13693  SetLevel2TrackMode(42);
13694  } break;
13695 
13696  case Deleting:
13697  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13698  Track->CopyFlag = false;
13699  UnicodeString MessageStr = "Selected area will be deleted - proceed?";
13700  int button = Application->MessageBox(MessageStr.c_str(), L"Please confirm", MB_YESNO);
13701  if(button == IDNO)
13702  {
13703  break;
13704  }
13705  bool EraseSuccessfulFlag, NeedToLink = false, TextChangesMade = false, GraphicChangesMade = false;
13706  int ErasedTrackVectorPosition;
13707  Screen->Cursor = TCursor(-11); // Hourglass;
13708  InfoPanel->Visible = true;
13709  InfoPanel->Caption = "DELETING: Please wait";
13710  InfoPanel->Update();
13711  for(int H = SelectRect.left; H < SelectRect.right; H++)
13712  {
13713  for(int V = SelectRect.top; V < SelectRect.bottom; V++)
13714  {
13715  Track->EraseTrackElement(3, H, V, ErasedTrackVectorPosition, EraseSuccessfulFlag, false);
13716  if(EraseSuccessfulFlag)
13717  {
13718  if(ErasedTrackVectorPosition > -1)
13719  EveryPrefDir->RealignAfterTrackErase(3, ErasedTrackVectorPosition);
13720  NeedToLink = true;
13721  }
13722  }
13723  }
13724  // erase text elements that fall within selected region
13725  int LowSelectHPos = SelectRect.left * 16;
13726  int HighSelectHPos = SelectRect.right * 16;
13727  int LowSelectVPos = SelectRect.top * 16;
13728  int HighSelectVPos = SelectRect.bottom * 16;
13729  if(!TextHandler->TextVector.empty()) // skip iteration if empty else have an error
13730  {
13731  for(TTextHandler::TTextVectorIterator TextPtr = (TextHandler->TextVector.end() - 1); TextPtr >= TextHandler->TextVector.begin();
13732  TextPtr--) // reverse to prevent skipping during erase
13733  {
13734  AnsiString Check = TextPtr->TextString;
13735  if((TextPtr->HPos >= LowSelectHPos) && (TextPtr->HPos < HighSelectHPos) && (TextPtr->VPos >= LowSelectVPos) && (TextPtr->VPos <
13736  HighSelectVPos))
13737  {
13738  if(TextHandler->TextErase(3, TextPtr->HPos, TextPtr->VPos, AnsiString("")))
13739  {;
13740  } // unused condition
13741  TextChangesMade = true;
13742  }
13743  }
13744  }
13745  // erase graphic elements that fall within selected region
13746  if(!Track->UserGraphicVector.empty()) // skip iteration if empty else have an error
13747  {
13748 
13749 //Isglassen05 (vilhelmgg@gmail.com) reported an error via email and attached an error file on 31/07/20. The error was in the following line which was:
13750 
13751 // for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->SelectGraphicVector.end() - 1); GraphicPtr >= Track->SelectGraphicVector.begin();
13752 // GraphicPtr--) // reverse to prevent skipping during erase
13753 
13754 //i.e if the railway included one or more user graphics but the SelectGraphicVector didn't include any, then GraphicPtr wouldn't point to anything and the program would fail
13755 //corrected 01/08/20 by using UserGraphicVector (as it should have been) for SelectGraphicVector. New version v2.4.3.
13756 
13757  for(TTrack::TUserGraphicVector::iterator GraphicPtr = (Track->UserGraphicVector.end() - 1); GraphicPtr >= Track->UserGraphicVector.begin();
13758  GraphicPtr--) // reverse to prevent skipping during erase
13759  {
13760  if((GraphicPtr->HPos >= LowSelectHPos) && ((GraphicPtr->HPos + GraphicPtr->Width) < HighSelectHPos) && (GraphicPtr->VPos >= LowSelectVPos)
13761  && ((GraphicPtr->VPos + GraphicPtr->Height) < HighSelectVPos))
13762  {
13763  for(TTrack::TUserGraphicVector::iterator UserGraphicPtr = (Track->UserGraphicVector.end() - 1);
13764  UserGraphicPtr >= Track->UserGraphicVector.begin(); UserGraphicPtr--) // reverse to prevent skipping during erase
13765  {
13766  if((UserGraphicPtr->HPos == GraphicPtr->HPos) && (UserGraphicPtr->VPos == GraphicPtr->VPos) &&
13767  (UserGraphicPtr->Width == GraphicPtr->Width) && (UserGraphicPtr->Height == GraphicPtr->Height) &&
13768  (UserGraphicPtr->FileName == GraphicPtr->FileName))
13769  {
13770  Track->UserGraphicVector.erase(UserGraphicPtr);
13771  GraphicChangesMade = true;
13772  }
13773  }
13774  }
13775  }
13776  }
13777  // clear the selectvectors
13779  TextHandler->SelectTextVector.clear();
13780  Track->SelectGraphicVector.clear();
13781  Track->CheckMapAndTrack(10); // test
13782  Track->CheckMapAndInactiveTrack(9); // test
13783  Track->CheckLocationNameMultiMap(15); // test
13784  // Track->SetTrackFinished(!NeedToLink); This is an error (see Sam Wainwright email of 24/08/17 & devhistory.txt
13785  // if track not linked to begin with then becomes linked if NeedToLink false
13786  if(NeedToLink)
13787  Track->SetTrackFinished(false); // corrected for v2.1.0
13788  if(NeedToLink || TextChangesMade || GraphicChangesMade)
13789  {
13790  ResetChangedFileDataAndCaption(21, true); // true for NonPrefDirChangesMade
13791  }
13792  Screen->Cursor = TCursor(-2); // Arrow;
13795  SetLevel1Mode(80);
13797  // No further recursion in AddTrack so OK
13798  UserGraphicReselectPanel->Visible = false;
13799  SetLevel2TrackMode(43);
13800  } break;
13801 
13802  default:
13803  // No further recursion in TrackMode so OK
13804  Track->CopyFlag = false;
13806  SetLevel1Mode(21);
13807  UserGraphicReselectPanel->Visible = false;
13808  break;
13809  }
13810  Utilities->CallLogPop(107);
13811 }
13812 
13813 // ---------------------------------------------------------------------------
13814 
13816 {
13817  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2PrefDirMode");
13818  if(Level1Mode != PrefDirMode)
13819  {
13820  // No further recursion in BaseMode so OK
13821  Level1Mode = BaseMode;
13822  SetLevel1Mode(22);
13823  Utilities->CallLogPop(108);
13824  return;
13825  }
13827  {
13828  Utilities->CallLogPop(109);
13829  return;
13830  }
13831 
13832  switch(Level2PrefDirMode) // use the data member
13833  {
13834  case PrefDirContinuing:
13835  { // have to use braces as otherwise the default case bypasses the initialisation of these local variables
13836  InfoPanel->Visible = true;
13837  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
13838  {
13839  AddPrefDirButton->Enabled = true; // this and the line below are to remove focus from any other button that might have it, prior to
13840  AddPrefDirButton->SetFocus(); // disabling the AddPrefDir button, so pressing enter does nothing, it is reset to the AddPrefDir
13841  }
13842  AddPrefDirButton->Enabled = false; // button later if it becomes enabled
13843  DeleteOnePrefDirButton->Enabled = false;
13844  bool LeadingPointsAtLastElement = false;
13845  if(!ConstructPrefDir->EndPossible(0, LeadingPointsAtLastElement))
13846  {
13847  if(LeadingPointsAtLastElement) // size must be > 1
13848  {
13849  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Can't end on leading points, select next location or truncate";
13850  DeleteOnePrefDirButton->Enabled = true;
13851  }
13852  else // size == 1, DeleteOnePrefDirButton->Enabled remains false
13853  {
13854  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Select next preferred direction location (right click to truncate)";
13855  }
13856  }
13857  else // size > 1 & EndPossible
13858  {
13859  InfoPanel->Caption = "PREFERRED DIRECTION SETTING: Add selection or select next location (right click to truncate)";
13860  if(!Display->ZoomOutFlag) // can't set focus if zoomed out, get an error - added this condition for v0.4d
13861  {
13862  AddPrefDirButton->Enabled = true;
13863  AddPrefDirButton->SetFocus(); // so can just press 'Enter' key
13864  }
13865  DeleteOnePrefDirButton->Enabled = true;
13866  }
13867  ExitPrefDirButton->Enabled = true;
13868  ClearandRebuildRailway(40); // to show truncated PrefDirs
13869  } break;
13870 
13871  case PrefDirSelecting:
13872  ResetSelectRect(); // so a viewpoint change before a new SelectRect chosen doesn't redisplay the old SelectRect
13873  InfoPanel->Visible = true;
13874  InfoPanel->Caption = "SELECTING: Select area - click left mouse && drag";
13875  SelectMenuItem->Enabled = false;
13876  ReselectMenuItem->Enabled = false;
13877  CancelSelectionMenuItem->Enabled = true;
13878  break;
13879 
13880  default:
13881  // No further recursion in PrefDirMode so OK
13883  SetLevel1Mode(23);
13884  break;
13885  }
13886  Utilities->CallLogPop(110);
13887 }
13888 
13889 // ---------------------------------------------------------------------------
13890 
13892 {
13893  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLevel2OperMode");
13894  if(Level1Mode != OperMode)
13895  {
13896  // No further recursion in BaseMode so OK
13897  Level1Mode = BaseMode;
13898  SetLevel1Mode(24);
13899  Utilities->CallLogPop(111);
13900  return;
13901  }
13902  if(Level2OperMode == NoOperMode)
13903  {
13904  Utilities->CallLogPop(112);
13905  return;
13906  }
13907  CallingOnButton->Visible = true;
13908  PresetAutoSigRoutesButton->Visible = false;
13909  switch(Level2OperMode) // use the data member
13910  {
13911  case Operating:
13912  { // have to use braces as otherwise the default case bypasses the initialisation of local variables
13913  OperateButton->Enabled = true;
13914  OperateButton->Glyph->LoadFromResourceName(0, "PauseGraphic");
13915  ExitOperationButton->Enabled = true;
13916  TTClockAdjButton->Enabled = false;
13917  if(TTClockSpeed == 2)
13918  TTClockSpeedLabel->Caption = "x2";
13919  else if(TTClockSpeed == 4)
13920  TTClockSpeedLabel->Caption = "x4";
13921  else if(TTClockSpeed == 8)
13922  TTClockSpeedLabel->Caption = "x8";
13923  else if(TTClockSpeed == 16)
13924  TTClockSpeedLabel->Caption = "x16";
13925  else if(TTClockSpeed == 0.5)
13926  TTClockSpeedLabel->Caption = "x1/2";
13927  else if(TTClockSpeed == 0.25)
13928  TTClockSpeedLabel->Caption = "x1/4";
13929  else if(TTClockSpeed == 0.125)
13930  TTClockSpeedLabel->Caption = "x1/8";
13931  else if(TTClockSpeed == 0.0625)
13932  TTClockSpeedLabel->Caption = "x1/16";
13933  else
13934  {
13935  TTClockSpeed = 1;
13936  TTClockSpeedLabel->Caption = "x1";
13937  }
13938  AnsiString TimeMessage = Utilities->Format96HHMMSS(TDateTime(PauseEntryRestartTime)) + ": ";
13940  {
13941  // send message to performance log
13942  if(TTClockSpeed == 2)
13943  Display->PerformanceLog(6, TimeMessage + "Timetable clock speed changed to twice normal");
13944  else if(TTClockSpeed == 4)
13945  Display->PerformanceLog(7, TimeMessage + "Timetable clock speed changed to four times normal");
13946  else if(TTClockSpeed == 8)
13947  Display->PerformanceLog(8, TimeMessage + "Timetable clock speed changed to eight times normal");
13948  else if(TTClockSpeed == 16)
13949  Display->PerformanceLog(9, TimeMessage + "Timetable clock speed changed to sixteen times normal");
13950  else if(TTClockSpeed == 0.5)
13951  Display->PerformanceLog(10, TimeMessage + "Timetable clock speed changed to half normal");
13952  else if(TTClockSpeed == 0.25)
13953  Display->PerformanceLog(11, TimeMessage + "Timetable clock speed changed to quarter normal");
13954  else if(TTClockSpeed == 0.125)
13955  Display->PerformanceLog(14, TimeMessage + "Timetable clock speed changed to one eighth normal");
13956  else if(TTClockSpeed == 0.0625)
13957  Display->PerformanceLog(15, TimeMessage + "Timetable clock speed changed to one sixteenth normal");
13958  else
13959  Display->PerformanceLog(12, TimeMessage + "Timetable clock speed changed to normal");
13960  }
13961  double TTClockTimeChange = double(TrainController->RestartTime) - PauseEntryRestartTime;
13962  if(TTClockTimeChange > 0.000347) // 30 seconds, min increase is 1 minute & don't trust doubles to stay exactly equal
13963  {
13964  // send message to performance log
13965  int MinsIncrease = ((TTClockTimeChange * 1440) + 0.5); // add 30 secs to ensure truncates correctly
13966  int HoursIncrease = 0;
13967  while(MinsIncrease >= 60)
13968  {
13969  HoursIncrease++;
13970  MinsIncrease -= 60;
13971  }
13972  if(HoursIncrease == 0)
13973  TimeMessage += "Timetable clock incremented by " + AnsiString(MinsIncrease) + "m";
13974  else if(MinsIncrease == 0)
13975  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h";
13976  else
13977  TimeMessage += "Timetable clock incremented by " + AnsiString(HoursIncrease) + "h " + AnsiString(MinsIncrease) + "m";
13978  Display->PerformanceLog(13, TimeMessage);
13979  }
13980  WarningHover = false;
13983  {
13984  MTBFEditBox->Visible = true;
13985  MTBFEditBox->Text = AnsiString(TrainController->AvHoursIntValue);
13986  MTBFEditBox->ReadOnly = true; // because this is not prestart mode
13987  MTBFLabel->Visible = true;
13988  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13990  }
13991  else
13992  {
13993  MTBFEditBox->Visible = false;
13994  MTBFEditBox->Text = "";
13995  MTBFLabel->Visible = false;
13996  MTBFLabel->Caption = "Mean time between\ntrain failures in\ntimetable hours";
13998  }
13999  TrainController->BaseTime = TDateTime::CurrentDateTime();
14000 // StopTTClockFlag already false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
14001  } break;
14002 
14003  case Paused:
14004  OperateButton->Enabled = true;
14005  OperateButton->Glyph->LoadFromResourceName(0, "RunGraphic");
14006  ExitOperationButton->Enabled = true;
14007  TTClockAdjButton->Enabled = true;
14012 // StopTTClockFlag stays false because TTClock stopped by condition "if(!TrainController->StopTTClockFlag && (Level2OperMode == Operating))" in MasterClockTimer function
14015  break;
14016 
14017  // don't need a separate case for PreStart
14018 
14019  default:
14020  // No further recursion in OperMode so OK
14021  Level1Mode = OperMode;
14022  SetLevel1Mode(25);
14023  break;
14024  }
14025  Utilities->CallLogPop(113);
14026 }
14027 
14028 // ---------------------------------------------------------------------------
14029 
14030 void TInterface::ApproachLocking(int Caller, TDateTime TTClockTime)
14031 {
14032  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ApproachLocking");
14033  float LockDelay = 120.0;
14034 
14035  if(!AllRoutes->LockedRouteVector.empty())
14036  {
14037  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.end() - 1; LRVIT >= AllRoutes->LockedRouteVector.begin(); LRVIT--)
14038  {
14039  bool BreakFlag = false;
14040  if(AllRoutes->TrackIsInARoute(5, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
14041  {
14042  TOneRoute &Route = AllRoutes->GetModifiableRouteAt(0, LRVIT->RouteNumber);
14043  if((TTClockTime - LRVIT->LockStartTime) > TDateTime(LockDelay / 86400))
14044  {
14045  TrainController->LogEvent("LockedRouteRemoved," + AnsiString(LRVIT->TruncateTrackVectorPosition) + "," +
14046  AnsiString(LRVIT->LastTrackVectorPosition));
14047  while(Route.LastElementPtr(9)->GetTrackVectorPosition() != LRVIT->TruncateTrackVectorPosition)
14048  { // examine the element one earlier in the route than the last
14049  if(!(AllRoutes->TrackIsInARoute(6, Route.LastElementPtr(10)->Conn[Route.LastElementPtr(11)->GetELinkPos()],
14050  Route.LastElementPtr(12)->ConnLinkPos[Route.LastElementPtr(13)->GetELinkPos()])))
14051  {
14052  BreakFlag = true;
14053  }
14054  AllRoutes->RemoveRouteElement(1, Route.LastElementPtr(14)->HLoc, Route.LastElementPtr(15)->VLoc, Route.LastElementPtr(16)->GetELink());
14055  if(BreakFlag)
14056  break; // train removed earlier element from route so stop here
14057  }
14058  if(!BreakFlag)
14059  { // still need to remove the element at the TruncateTrackVectorPosition
14060  if(Route.LastElementPtr(17)->GetTrackVectorPosition() == LRVIT->TruncateTrackVectorPosition)
14061  {
14062  AllRoutes->RemoveRouteElement(2, Route.LastElementPtr(18)->HLoc, Route.LastElementPtr(19)->VLoc,
14063  Route.LastElementPtr(20)->GetELink());
14064  }
14065  }
14066  AllRoutes->CheckMapAndRoutes(10); // test
14067  AllRoutes->LockedRouteVector.erase(LRVIT);
14068  if(!Display->ZoomOutFlag)
14069  ClearandRebuildRailway(17); // to get rid of route graphics
14071  }
14072  }
14073  else
14074  {
14075  AllRoutes->LockedRouteVector.erase(LRVIT);
14076  // if end element not in route then a train must have entered it from the wrong end and erased the whole route,
14077  // hence no longer needed so get rid of it
14078  }
14079  }
14080  }
14081  Utilities->CallLogPop(743);
14082 }
14083 
14084 // ---------------------------------------------------------------------------
14085 
14086 void TInterface::ContinuationAutoSignals(int Caller, TDateTime TTClockTime)
14087 {
14088  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ContinuationAutoSignals");
14090  {
14092  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
14093  AutoSigVectorIT--)
14094  {
14095  // Below added at v2.1.0 to prevent locked autosig continuation routes from clearing signals
14096  // need to identify the Continuation element in the route & check if it's in a locked route. If it is then don't call
14097  // SetTrailingSignalsOnContinuationRoute as all signals must stay red.
14098  TPrefDirElement TempPrefDirElement;
14099  int TempLockedVectorNumber;
14100  int LastRouteElement = AllRoutes->GetFixedRouteAt(220, AutoSigVectorIT->RouteNumber).PrefDirSize() - 1;
14101  int TVNum = AllRoutes->GetFixedRouteAt(221, AutoSigVectorIT->RouteNumber).GetFixedPrefDirElementAt(246, LastRouteElement).GetTrackVectorPosition();
14102  // this will be a continuation (error thrown in SetTrailingSignalsOnContinuationRoute if not) & XLinkPos is always 0 for
14103  // route exiting at a continuation
14104  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(14, TVNum, 0, TempPrefDirElement, TempLockedVectorNumber))
14105  {
14106  continue;
14107  }
14108  // end of additions
14109  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->FirstDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 0))
14110  {
14111  AllRoutes->SetTrailingSignalsOnContinuationRoute(1, AutoSigVectorIT->RouteNumber, 0);
14112  AutoSigVectorIT->AccessNumber++;
14113  continue;
14114  }
14115  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->SecondDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 1))
14116  {
14117  AllRoutes->SetTrailingSignalsOnContinuationRoute(2, AutoSigVectorIT->RouteNumber, 1);
14118  AutoSigVectorIT->AccessNumber++;
14119  continue;
14120  }
14121  if(((TTClockTime - AutoSigVectorIT->PassoutTime) > TDateTime(AutoSigVectorIT->ThirdDelay / 86400)) && (AutoSigVectorIT->AccessNumber == 2))
14122  {
14123  AllRoutes->SetTrailingSignalsOnContinuationRoute(3, AutoSigVectorIT->RouteNumber, 2);
14124  AutoSigVectorIT->AccessNumber++;
14125  continue;
14126  }
14127  }
14128  // examine all vector for any expired values & erase
14129  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
14130  AutoSigVectorIT--)
14131  {
14132  if(AutoSigVectorIT->AccessNumber > 2)
14133  {
14134  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT); // erase expired entries - reverse interation so OK to erase
14135  }
14136  }
14137  }
14138  Utilities->CallLogPop(744);
14139 }
14140 
14141 // ---------------------------------------------------------------------------
14142 
14144 {
14145  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackTrainFloat");
14146 
14147  TPoint MousePoint = Mouse->CursorPos;
14148  int ScreenX = MousePoint.x - MainScreen->ClientOrigin.x;
14149  int ScreenY = MousePoint.y - MainScreen->ClientOrigin.y;
14150 
14151  if((ScreenX > (MainScreen->Width - 1)) || (ScreenY > (MainScreen->Height - 1)) || (ScreenX < 0) || (ScreenY < 0))
14152  {
14153  FloatingPanel->Visible = false;
14154  Utilities->CallLogPop(1432);
14155  return;
14156  }
14157 
14158  if(PerformancePanel->Visible)
14159  {
14160  if((MousePoint.x >= PerformancePanel->Left) && (MousePoint.x <= (PerformancePanel->Left + PerformancePanel->Width)) &&
14161  ((MousePoint.y - ClientOrigin.y) >= PerformancePanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
14162  (PerformancePanel->Top + PerformancePanel->Height)))
14163  { // dont show floating window if mouse over performance panel
14164  FloatingPanel->Visible = false;
14165  Utilities->CallLogPop(1715);
14166  return;
14167  }
14168  }
14169 
14170  if(OperatorActionPanel->Visible) // added at v2.3.0 as showed info from behind panel - thanks to Xeon who notified me in email of 15/10/19
14171  {
14172  if((MousePoint.x >= OperatorActionPanel->Left) && (MousePoint.x <= (OperatorActionPanel->Left + OperatorActionPanel->Width)) &&
14173  ((MousePoint.y - ClientOrigin.y) >= OperatorActionPanel->Top) && ((MousePoint.y - ClientOrigin.y) <=
14174  (OperatorActionPanel->Top + OperatorActionPanel->Height)))
14175  { // dont show floating window if mouse over OperatorActionPanel
14176  FloatingPanel->Visible = false;
14177  Utilities->CallLogPop(2098);
14178  return;
14179  }
14180  }
14181 
14182  AnsiString TrackFloat = "", TrainStatusFloat = "", TrainTTFloat = "";
14183 
14184  bool ShowTrackFloatFlag = false, ShowTrainStatusFloatFlag = false, ShowTrainTTFloatFlag = false;
14185  int HLoc, VLoc;
14186 
14187  Track->GetTrackLocsFromScreenPos(4, HLoc, VLoc, ScreenX, ScreenY);
14188 
14189  if(Display->ZoomOutFlag)
14190  {
14191  Utilities->CallLogPop(1123);
14192  return;
14193  }
14194  if(TrackInfoOnOffMenuItem->Caption == "Hide")
14195  {
14196  bool ActiveTrackFoundFlag = false, InactiveTrackFoundFlag = false, TwoTrack = false;
14197  AnsiString Length01Str = "", Length23Str = "", SpeedLimit01Str = "", SpeedLimit23Str = "";
14198  AnsiString StationEntryStopLinkPos1Str = "", StationEntryStopLinkPos2Str = "";
14199  AnsiString ATrackSN = "", ATrackTN = "", IATrackSN = "", LengthAndSpeedCaption = "";
14200  AnsiString SigAspectString = ""; // new at version 0.6
14201  int ActiveVecPos = Track->GetVectorPositionFromTrackMap(5, HLoc, VLoc, ActiveTrackFoundFlag);
14202  TTrack::TIMPair InactiveVecPositions = Track->GetVectorPositionsFromInactiveTrackMap(3, HLoc, VLoc, InactiveTrackFoundFlag);
14203  TTrackElement ActiveTrackElement, InactiveTrackElement;
14204  if(InactiveTrackFoundFlag)
14205  {
14206  InactiveTrackElement = Track->InactiveTrackElementAt(32, InactiveVecPositions.first); // only need one for the name
14207  IATrackSN = InactiveTrackElement.LocationName;
14208  }
14209  if(ActiveTrackFoundFlag)
14210  {
14211  ActiveTrackElement = Track->TrackElementAt(449, ActiveVecPos);
14212  ATrackSN = ActiveTrackElement.LocationName;
14213  StationEntryStopLinkPos1Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos1);
14214  StationEntryStopLinkPos2Str = AnsiString(ActiveTrackElement.StationEntryStopLinkPos2);
14215  ATrackTN = ActiveTrackElement.ActiveTrackElementName;
14216  if((ATrackTN != "") && (!InactiveTrackFoundFlag || ((InactiveTrackElement.TrackType != Platform) &&
14217  (InactiveTrackElement.TrackType != NamedNonStationLocation)) ||
14218  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName)))
14219  {
14220  ShowMessage("Error - Track has timetable name without corresponding plat/named loc");
14221  }
14222  if(InactiveTrackFoundFlag && ((InactiveTrackElement.TrackType == Platform) || (InactiveTrackElement.TrackType == NamedNonStationLocation)) &&
14223  (InactiveTrackElement.LocationName != ActiveTrackElement.ActiveTrackElementName))
14224  {
14225  ShowMessage("Error - plat/named loc and track have different names, or plat/named loc named but not track");
14226  }
14227  if((ActiveTrackElement.TrackType == Points) || (ActiveTrackElement.TrackType == Bridge) || (ActiveTrackElement.TrackType == Crossover))
14228  {
14229  TwoTrack = true;
14230  }
14231  Length01Str = AnsiString(ActiveTrackElement.Length01);
14232  if(Length01Str == "-1")
14233  Length01Str = "Not Set";
14234  SpeedLimit01Str = AnsiString(ActiveTrackElement.SpeedLimit01);
14235  if(SpeedLimit01Str == "-1")
14236  SpeedLimit01Str = "Not Set";
14237  if(TwoTrack)
14238  {
14239  Length23Str = AnsiString(ActiveTrackElement.Length23);
14240  if(Length23Str == "-1")
14241  Length23Str = "Not Set"; // shouldn't be -1 but leave in
14242  SpeedLimit23Str = AnsiString(ActiveTrackElement.SpeedLimit23);
14243  if(SpeedLimit23Str == "-1")
14244  SpeedLimit23Str = "Not Set"; // shouldn't be -1 but leave in
14245  if((ActiveTrackElement.TrackType == Points) && (ActiveTrackElement.SpeedTag < 132))
14246  {
14247  LengthAndSpeedCaption = "Straight track length = " + Length01Str + " m" + '\n' + "Diverging track length = " + Length23Str + " m" + '\n' +
14248  "Straight track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Diverging track speed limit = " + SpeedLimit23Str + " km/h";
14249  }
14250  else if(ActiveTrackElement.TrackType == Points)
14251  {
14252  LengthAndSpeedCaption = "Left diverging track length = " + Length01Str + " m" + '\n' + "Right diverging track length = " + Length23Str +
14253  " m" + '\n' + "Left diverging track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Right diverging track Speed Limit = " +
14254  SpeedLimit23Str + " km/h";
14255  }
14256  else if(ActiveTrackElement.TrackType == Crossover)
14257  // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
14258  {
14259  if((ActiveTrackElement.SpeedTag == 15) || (ActiveTrackElement.SpeedTag == 46))
14260  {
14261  LengthAndSpeedCaption = "Horizontal track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
14262  "Horizontal track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
14263  }
14264  else if(ActiveTrackElement.SpeedTag == 47)
14265  {
14266  LengthAndSpeedCaption = "Horizontal track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
14267  "Horizontal track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
14268  }
14269  else if(ActiveTrackElement.SpeedTag == 45)
14270  {
14271  LengthAndSpeedCaption = "Vertical track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str + " m" + '\n' +
14272  "Vertical track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit23Str + " km/h";
14273  }
14274  else if(ActiveTrackElement.SpeedTag == 44)
14275  {
14276  LengthAndSpeedCaption = "Vertical track length = " + Length23Str + " m" + '\n' + "Other track length = " + Length01Str + " m" + '\n' +
14277  "Vertical track speed limit = " + SpeedLimit23Str + " km/h" + '\n' + "Other track speed limit = " + SpeedLimit01Str + " km/h";
14278  }
14279  else if(ActiveTrackElement.SpeedTag == 16)
14280  {
14281  LengthAndSpeedCaption = "Top left to bottom right track length = " + Length01Str + " m" + '\n' + "Other track length = " + Length23Str +
14282  " m" + '\n' + "Top left to bottom right track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Other track speed limit = " +
14283  SpeedLimit23Str + " km/h";
14284  }
14285  }
14286  else // bridge
14287  {
14288  LengthAndSpeedCaption = "Top track length = " + Length01Str + " m" + '\n' + "Bottom track length = " + Length23Str + " m" + '\n' +
14289  "Top track speed limit = " + SpeedLimit01Str + " km/h" + '\n' + "Bottom track speed limit = " + SpeedLimit23Str + " km/h";
14290  }
14291  }
14292  else
14293  {
14294  LengthAndSpeedCaption = "Track length = " + Length01Str + " m" + '\n' + "Track speed limit = " + SpeedLimit01Str + " km/h";
14295  }
14296  }
14297  if(ActiveTrackFoundFlag)
14298  {
14299  // note that now the "In timetable..." line removed much of the below could be simplified, but leave as is
14300  // in case wish to resurrect this line for any reason
14301  ShowTrackFloatFlag = true;
14302  if(ATrackTN != "") // has a timetable name & therefore has a valid platform or non-station name
14303  {
14304  TrackFloat = "Location = " + ATrackTN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
14305  }
14306  else if(ATrackSN != "") // no timetable name but location name, i.e. a footcrossing
14307  {
14308  TrackFloat = "Location = " + ATrackSN + '\n' + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
14309  }
14310 
14311  else if(InactiveTrackFoundFlag) // no timetable name yet but unnamed inactive element at same location (can't be a parapet if active element there)
14312  {
14313  TrackFloat = "Location unnamed\n" + LengthAndSpeedCaption + '\n' + "ID = " + AnsiString(ActiveTrackElement.ElementID);
14314  }
14315 
14316  else // no timetable or location name, just track
14317  {
14318  TrackFloat = LengthAndSpeedCaption + '\n' + "Track Element ID = " + AnsiString(ActiveTrackElement.ElementID);
14319  }
14320  if(ActiveTrackElement.TrackType == SignalPost) // new for version 0.6
14321  {
14322  if(ActiveTrackElement.SigAspect == TTrackElement::ThreeAspect)
14323  {
14324  SigAspectString = "\nThree-aspect signal";
14325  }
14326  else if(ActiveTrackElement.SigAspect == TTrackElement::TwoAspect)
14327  {
14328  SigAspectString = "\nTwo-aspect signal";
14329  }
14330  else if(ActiveTrackElement.SigAspect == TTrackElement::GroundSignal)
14331  {
14332  SigAspectString = "\nGround signal";
14333  }
14334  else
14335  {
14336  SigAspectString = "\nFour-aspect signal";
14337  }
14338  TrackFloat += SigAspectString;
14339  }
14340  } // if(ActiveFoundFlag)
14341  else if(InactiveTrackFoundFlag) // inactive element but no active element,
14342  // i.e. concourse or non-station name at a blank element
14343  {
14344  ShowTrackFloatFlag = true;
14345  if(InactiveTrackElement.TrackType != Parapet)
14346  {
14347  if(IATrackSN == "")
14348  {
14349  TrackFloat = "Location unnamed\nID = " + AnsiString(InactiveTrackElement.ElementID);
14350  }
14351  else
14352  {
14353  TrackFloat = "Location = " + IATrackSN + '\n' + "ID = " + AnsiString(InactiveTrackElement.ElementID);
14354  }
14355  }
14356  else // it is a parapet, just show the ID
14357  {
14358  TrackFloat = "ID = " + AnsiString(InactiveTrackElement.ElementID);
14359  }
14360  }
14361  }
14362 // end of TrackFloat section
14363 
14364  if(Level1Mode == OperMode && ((TrainStatusInfoOnOffMenuItem->Caption == "Hide Status") || (TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")))
14365  // if caption is 'Hide' label is required
14366  {
14367  bool FoundFlag;
14368  AnsiString FormatOneDPStr = "####0.0";
14369  AnsiString FormatNoDPStr = "#######0";
14370 // AnsiString Format5DPStr = "####0.00000"; //temporary
14371  AnsiString MaxBrakeStr = ""; // , EntrySpeedStr="", HalfStr="", FullStr="", MaxAtHalfStr="";//test
14372  AnsiString SpecialStr = "", MaxSpeedStr = "";
14373  int VecPos = Track->GetVectorPositionFromTrackMap(6, HLoc, VLoc, FoundFlag);
14374  if(FoundFlag)
14375  {
14376  if(Track->TrackElementAt(450, VecPos).TrainIDOnElement > -1)
14377  // if a bridge & 2 trains at that position will select the train with TrainIDOnElement set
14378  {
14380  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
14381  {
14382  ShowTrainStatusFloatFlag = true;
14383  AnsiString HeadCode = "", ServiceReferenceInfo = "", Status = "", CurrSpeedStr = "", BrakePCStr = "", NextStopStr = "", TimeLeftStr = "",
14384  TimeToNextMovementStr = "", MassStr = "", PowerStr = "";
14385  double CurrSpeed;
14386  MassStr = AnsiString::FormatFloat(FormatNoDPStr, ((double)Train.Mass) / 1000); // Te
14387  PowerStr = AnsiString::FormatFloat(FormatNoDPStr, Train.PowerAtRail / 1000 / 0.8); // kW
14388  if(Train.BeingCalledOn)
14389  MaxSpeedStr = "30";
14390  else
14391  MaxSpeedStr = AnsiString::FormatFloat(FormatNoDPStr, Train.MaxRunningSpeed);
14392  TDateTime ElapsedDeltaT = TrainController->TTClockTime - Train.EntryTime;
14393  TDateTime FirstHalfTimeDeltaT = Train.ExitTimeHalf - Train.EntryTime;
14394  TDateTime SecondHalfTimeDeltaT = Train.ExitTimeFull - Train.EntryTime - FirstHalfTimeDeltaT;
14395  TDateTime TimeLeft;
14396  double BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
14397  MaxBrakeStr = AnsiString::FormatFloat(FormatNoDPStr, (Train.MaxBrakeRate * Train.Mass / 9810));
14398  HeadCode = Train.HeadCode;
14399  if(Train.TrainDataEntryPtr->NumberOfTrains > 1) // Service reference information added at v0.6b
14400  {
14401  if(Train.RepeatNumber == 0)
14402  {
14403  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
14404  ServiceReferenceInfo = "\nFirst service of ref. " + Train.TrainDataEntryPtr->ServiceReference;
14405  else
14406  ServiceReferenceInfo = "\nFirst service";
14407  }
14408  else if(HeadCode == Train.TrainDataEntryPtr->ServiceReference)
14409  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber);
14410  else
14411  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(Train.RepeatNumber) + " of ref. " +
14413  }
14414  else
14415  {
14416  if(HeadCode != Train.TrainDataEntryPtr->ServiceReference)
14417  ServiceReferenceInfo = "\nService reference " + Train.TrainDataEntryPtr->ServiceReference;
14418  }
14419  if(Train.Stopped())
14420  {
14421  if(Train.SignallerStopped)
14422  Status = "Stopped on signaller's instruction"; // if stopped for any other reason that will diplay
14423  if(Train.NotInService)
14424  Status = "Not in service"; // not used so far but leave it in
14425  if(Train.StoppedAtBuffers)
14426  Status = "Stopped at buffers";
14427  if(Train.StoppedAtSignal)
14428  Status = "Stopped at signal";
14429  if(Train.StoppedForTrainInFront)
14430  Status = "Stopped - forward track occupied"; // before station stop as want to display station stop if that set
14431  if(Train.StoppedAtLocation)
14432  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName;
14433  if((Train.StoppedAtLocation) && (Train.StoppedForTrainInFront))
14434  Status = "Stopped at " + Train.ActionVectorEntryPtr->LocationName + " + forward track occupied";
14435  if(Train.StoppedWithoutPower)
14436  {
14437  if(Train.TrainFailed)
14438  Status = "Stopped without power - train failed";
14439  else
14440  Status = "Stopped without power";
14441  }
14442  if(Train.StoppedAfterSPAD)
14443  Status = "Stopped - signal passed at danger";
14444  if(Train.Derailed)
14445  Status = "Derailed";
14446  if(Train.Crashed)
14447  Status = "Crashed";
14448  CurrSpeed = 0;
14449  }
14450  else if(Train.OneLengthAccelDecel)
14451  {
14452  if(Train.FirstHalfMove)
14453  {
14454  Status = "Accelerating"; // just display a linear speed rise over half length
14455  BrakePCRate = 0; // reset to proper value during braking
14456  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
14457  }
14458  else
14459  {
14460  BrakePCRate = Train.BrakeRate * 100.0 / Train.MaxBrakeRate;
14461  if(BrakePCRate < 55)
14462  Status = "Light braking";
14463  else if(BrakePCRate < 90)
14464  Status = "Heavy braking";
14465  else
14466  Status = "Emergency braking";
14467  CurrSpeed = Train.ExitSpeedHalf - 3.6 * (Train.BrakeRate * (TrainController->TTClockTime - Train.ExitTimeHalf) * 86400.0);
14468  }
14469  }
14470  else if(Train.BrakeRate > 0.01)
14471  {
14472  if(BrakePCRate < 55)
14473  Status = "Light braking";
14474  else if(BrakePCRate < 90)
14475  Status = "Heavy braking";
14476  else
14477  Status = "Emergency braking";
14478  CurrSpeed = Train.EntrySpeed - 3.6 * (Train.BrakeRate * ElapsedDeltaT * 86400.0);
14479  }
14480 
14481  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedHalf > (Train.EntrySpeed + 0.01)) && Train.FirstHalfMove)
14482  {
14483  Status = "Accelerating"; // just display a linear speed rise over half length
14484  CurrSpeed = Train.EntrySpeed + ((Train.ExitSpeedHalf - Train.EntrySpeed) * (double(ElapsedDeltaT) / double(FirstHalfTimeDeltaT)));
14485  }
14486 
14487  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull > (Train.ExitSpeedHalf + 0.01)) && !Train.FirstHalfMove)
14488  {
14489  Status = "Accelerating";
14490  CurrSpeed = Train.ExitSpeedHalf +
14491  ((Train.ExitSpeedFull - Train.ExitSpeedHalf) * (double(ElapsedDeltaT - FirstHalfTimeDeltaT) / double(SecondHalfTimeDeltaT)));
14492  }
14493 
14494  else if((Train.BrakeRate <= 0.01) && (Train.ExitSpeedFull <= Train.ExitSpeedHalf) && !Train.FirstHalfMove)
14495  {
14496  if(Train.PowerAtRail < 1)
14497  {
14498  if(Train.TrainFailed)
14499  {
14500  Status = "Coasting - train failed";
14501  }
14502  else
14503  {
14504  Status = "Coasting - no power";
14505  }
14506  CurrSpeed = Train.ExitSpeedFull;
14507  }
14508  else
14509  {
14510  Status = "Constant speed";
14511  CurrSpeed = Train.ExitSpeedFull;
14512  }
14513  }
14514 
14515  else // No braking, first half move, ExitSpeedHalf <= EntrySpeed
14516  {
14517  if(Train.PowerAtRail < 1) // as designed there is no way a vehicle can coast without having failed
14518  {
14519  if(Train.TrainFailed)
14520  {
14521  Status = "Coasting - train failed";
14522  }
14523  else
14524  {
14525  Status = "Coasting - no power";
14526  }
14527  CurrSpeed = Train.ExitSpeedHalf;
14528  }
14529  else
14530  {
14531  Status = "Constant speed";
14532  CurrSpeed = Train.ExitSpeedHalf;
14533  }
14534  }
14535  if(Train.TimetableFinished)
14536  {
14537  if(Train.TrainMode == Signaller)
14538  NextStopStr = "At signaller's discretion";
14539  else
14540  NextStopStr = "None";
14541  }
14542  else
14543  NextStopStr = Train.FloatingLabelNextString(0, Train.ActionVectorEntryPtr);
14544  if(Train.TrainMode == Signaller)
14545  {
14546  SpecialStr = "Train under signaller control" + AnsiString('\n');
14547  }
14548  else if(Train.BeingCalledOn && !Train.StoppedAtLocation)
14549  {
14550  SpecialStr = "Restricted speed - being called on" + AnsiString('\n');
14551  }
14552 
14553  double RemTimeHalf = 86400.0 * double(Train.ExitTimeHalf - TrainController->TTClockTime);
14554  if(RemTimeHalf < 0)
14555  RemTimeHalf = 0;
14556  double RemTimeFull = 86400.0 * double(Train.ExitTimeFull - TrainController->TTClockTime);
14557  if(RemTimeFull < 0)
14558  RemTimeFull = 0;
14559  if(RemTimeHalf > 0)
14560  TimeLeft = RemTimeHalf;
14561  else
14562  TimeLeft = RemTimeFull;
14563  TimeToNextMovementStr = "Time to next movement (sec) = " + TimeLeftStr.FormatFloat(FormatOneDPStr, TimeLeft);
14564  if(Train.Stopped())
14565  TimeToNextMovementStr = "";
14566  if(Train.Stopped())
14567  {
14568  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " +
14569  MaxSpeedStr + "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr +
14570  Status + '\n' + "Next: " + NextStopStr;
14571  }
14572  else
14573  {
14574  TrainStatusFloat = HeadCode + ": " + Train.TrainDataEntryPtr->Description + ServiceReferenceInfo + '\n' + "Maximum train speed " +
14575  MaxSpeedStr + "km/h; Power " + PowerStr + "kW" + '\n' + "Mass " + MassStr + "Te; Brakes " + MaxBrakeStr + "Te" + '\n' + SpecialStr +
14576  Status + ": " + CurrSpeedStr.FormatFloat(FormatNoDPStr, CurrSpeed) + "km/h" + '\n' + "Next: " + NextStopStr;
14577  }
14578  }
14579  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14580  {
14581  ShowTrainTTFloatFlag = true;
14582  TrainTTFloat = Train.FloatingTimetableString(0, Train.ActionVectorEntryPtr);
14583  }
14584  }
14585 
14586  else if(Track->TrackElementAt(666, VecPos).TrackType == Continuation)
14587  // always give train information if a train present, but if not & either of train status or timetable info
14588  // selected then give next expected train to enter, or 'No trains expected'
14589  {
14590  TrainStatusFloat = "No trains expected";
14591  TrainTTFloat = "No timetable";
14592  float EntrySpeed;
14593  int LineSpeedLimit = Track->TrackElementAt(906, VecPos).SpeedLimit01; // speed only in 01 as a continuation
14594  if(TrainStatusInfoOnOffMenuItem->Caption == "Hide Status")
14595  ShowTrainStatusFloatFlag = true;
14596  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14597  ShowTrainTTFloatFlag = true;
14599  {
14602  {
14603  while((CTEIt != TrainController->ContinuationTrainExpectationMultiMap.end()) && ((CTEIt->second.VectorPosition != VecPos) ||
14604  (CTEIt->second.TrainDataEntryPtr->TrainOperatingDataVector.at(CTEIt->second.RepeatNumber).RunningEntry != NotStarted)))
14605  {
14606  CTEIt++;
14607  }
14609  {
14610  TTrainDataEntry *TTDEPtr = CTEIt->second.TrainDataEntryPtr;
14611  AnsiString ServiceReferenceInfo = "";
14612  // Repeat information
14613  if(TTDEPtr->NumberOfTrains > 1) // Service reference information
14614  {
14615  if(CTEIt->second.RepeatNumber == 0)
14616  {
14617  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
14618  ServiceReferenceInfo = "\nFirst service of ref. " + TTDEPtr->ServiceReference;
14619  else
14620  ServiceReferenceInfo = "\nFirst service";
14621  }
14622  else if(CTEIt->second.HeadCode == TTDEPtr->ServiceReference)
14623  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber);
14624  else
14625  ServiceReferenceInfo = "\nRepeat service no. " + AnsiString(CTEIt->second.RepeatNumber) + " of ref. " +
14626  TTDEPtr->ServiceReference;
14627  }
14628  else
14629  {
14630  if(CTEIt->second.HeadCode != TTDEPtr->ServiceReference)
14631  ServiceReferenceInfo = "\nService reference " + TTDEPtr->ServiceReference;
14632  }
14633  if(TTDEPtr->ActionVector.at(0).SignallerControl) // entry at 0 is the start entry
14634  {
14635  SpecialStr = "\nTrain under signaller control";
14636  EntrySpeed = TTDEPtr->SignallerSpeed;
14637  if(EntrySpeed > LineSpeedLimit)
14638  EntrySpeed = LineSpeedLimit;
14639  }
14640  else
14641  {
14642  EntrySpeed = TTDEPtr->StartSpeed;
14643  if(EntrySpeed > LineSpeedLimit)
14644  EntrySpeed = LineSpeedLimit;
14645  }
14646  if((CTEIt->first + TDateTime(1.0 / 1440)) < TrainController->TTClockTime) // has to be at least 1 min late to show as late
14647  {
14648  TDateTime TempTime = CTEIt->first;
14649 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
14650  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
14651  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nDelayed, was due at " +
14652  Utilities->Format96HHMM(TempTime);
14653  }
14654  else
14655  {
14656  TDateTime TempTime = CTEIt->first;
14657 // need this because CTEIt points to a const object and shouldn't use FormatString on a const object
14658  TrainStatusFloat = CTEIt->second.HeadCode + ": " + CTEIt->second.Description + ServiceReferenceInfo + "\nEntry speed " +
14659  AnsiString::FormatFloat(FormatNoDPStr, EntrySpeed) + "km/h" + SpecialStr + "\nExpected at " +
14660  Utilities->Format96HHMM(TempTime);
14661  }
14662  if(TrainTTInfoOnOffMenuItem->Caption == "Hide Timetable")
14663  {
14664  if(!TTDEPtr->ActionVector.at(0).SignallerControl) // if signaller control there's no timetable & SpecialStr covers this
14665  {
14666  TrainTTFloat = TrainController->ContinuationEntryFloatingTTString(0, TTDEPtr, CTEIt->second.RepeatNumber,
14667  CTEIt->second.IncrementalMinutes, CTEIt->second.IncrementalDigits);
14668  }
14669  }
14670  }
14671  }
14672  }
14673  }
14674  }
14675  }
14676 
14677 // end of TrainFloat section
14678  AnsiString Caption;
14679 
14680  if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14681  {
14682  FloatingPanel->Visible = false;
14683  Utilities->CallLogPop(1485);
14684  return; // return with label invisible
14685  }
14686  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14687  {
14688  Caption = TrackFloat;
14689  }
14690  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14691  {
14692  Caption = TrainStatusFloat;
14693  }
14694  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && !ShowTrainTTFloatFlag)
14695  {
14696  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
14697  }
14698  else if(!ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14699  {
14700  if(TrainStatusFloat == "No trains expected")
14701  Caption = TrainStatusFloat;
14702  else
14703  Caption = TrainTTFloat;
14704  }
14705  else if(ShowTrackFloatFlag && !ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14706  {
14707  if(TrainStatusFloat == "No trains expected")
14708  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
14709  else
14710  Caption = TrainTTFloat + '\n' + '\n' + TrackFloat;
14711  }
14712  else if(!ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14713  {
14714  if(TrainStatusFloat == "No trains expected")
14715  Caption = TrainStatusFloat;
14716  else
14717  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat;
14718  }
14719  else if(ShowTrackFloatFlag && ShowTrainStatusFloatFlag && ShowTrainTTFloatFlag)
14720  {
14721  if(TrainStatusFloat == "No trains expected")
14722  Caption = TrainStatusFloat + '\n' + '\n' + TrackFloat;
14723  else
14724  Caption = TrainStatusFloat + '\n' + '\n' + TrainTTFloat + '\n' + '\n' + TrackFloat;
14725  }
14726 
14727  int Left = ScreenX + MainScreen->Left + 16; // so lhs of window is one element to the right of the mouse pos
14728 
14729 // this offset is because window position is relative to the interface form, whereas ScreenX & Y are relative to the MainScreen, which is
14730 // offset 32 to the right and 95 down from the interface form
14731  if((Left + FloatingPanel->Width) > MainScreen->Left + MainScreen->Width)
14732  Left = ScreenX - FloatingPanel->Width + 16; // so rhs of window is one element to the left of the mouse pos (+32 would be at mouse pos)
14733  int Top = ScreenY + MainScreen->Top + 16; // so top of window is one element below the mouse pos (ScreenY + MainScreen->Top would be at mouse pos)
14734 
14735  if((Top + FloatingPanel->Height) > MainScreen->Top + MainScreen->Height)
14736  {
14737  Top = ScreenY - FloatingPanel->Height + 79; // so bottom of window is one element above the mouse pos (95 would be at mouse pos)
14738  // but, top may now be off the top of the screen, if so position at the top of the screen, as always need to see the top, if have to
14739  // lose something then it's best to be from the bottom
14740  if(Top < 30) // use 30 instead of MainScreen->Top [95] as top can go off MainScreen providing it doesn't reach the information panel, as that would
14741  // obscure the window
14742  {
14743  Top = 30;
14744  }
14745  }
14746  if((Left != FloatingPanel->Left) || (Top != FloatingPanel->Top))
14747  {
14748  FloatingPanel->Visible = false; // so doesn't flicker when reposition
14749  FloatingPanel->Left = Left;
14750  FloatingPanel->Top = Top;
14751  Utilities->CallLogPop(1917);
14752  return;
14753  }
14754 
14755  FloatingLabel->Caption = Caption;
14756  FloatingPanel->Visible = true;
14757  FloatingPanel->BringToFront();
14758  Utilities->CallLogPop(746);
14759 }
14760 
14761 // ---------------------------------------------------------------------------
14762 
14763 void TInterface::FlashingGraphics(int Caller, TDateTime Now)
14764  // following section checks to see if GapFlashFlag set & flashes the Gap graphics if so
14765  // Gap flashing is cancelled on any mousedown event
14766 
14767  // deal with flashing GapFlash graphics (only in basic mode so no need to check for trains)
14768 {
14769  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FlashingGraphics");
14771  {
14772  if(WarningFlash)
14773  {
14774  Track->GapFlashGreen->PlotOverlay(4, Display); // only plotted if PlotOverlay reset
14776  }
14777  else
14778  {
14779  Track->GapFlashGreen->PlotOriginal(17, Display); // only plotted if PlotOverlay set
14781  }
14782  }
14783 
14785  {
14786  if(WarningFlash)
14787  {
14792  Display->Update();
14793  }
14794  else
14795  {
14800  Display->Update();
14801  }
14802  }
14803 
14804 // deal with other flashing graphics
14806  {
14807  if((Now - RouteFlashStartTime) < TDateTime(RouteFlashDuration / 86400))
14808  {
14809  // cancel if train is moving & arrives on any part of flashing route
14811  {
14812  Track->RouteFlashFlag = false;
14814  ClearandRebuildRailway(18); // because using ConstructRoute->RouteFlash.PlotOriginal() can plot wrong point fillet as well as
14815  // original (if proposed route would change point). With this can dispense with ConstructRoute->RouteFlash.PlotOriginal()
14816  Utilities->CallLogPop(75);
14817  return;
14818  }
14819 
14820  InfoPanel->Visible = true;
14821  if(Level2OperMode == PreStart)
14822  InfoPanel->Caption = "PRE-START: Route setting in progress";
14823  else
14824  InfoPanel->Caption = "OPERATING: Route setting in progress";
14825  if(WarningFlash)
14826  {
14828  }
14829  else
14830  {
14832  }
14833  }
14834  else
14835  {
14836 // ConstructRoute->RouteFlash.PlotOriginal(); don't need with clearand....
14837 // stop clock while converting route as can take several seconds
14838  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
14840  if(PreferredRouteFlag)
14842  else
14844  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
14845  TrainController->BaseTime = TDateTime::CurrentDateTime();
14847  Track->RouteFlashFlag = false;
14849  ClearandRebuildRailway(19); // if drop this ensure replot trains after replot routes else route will overwrite a train
14850  }
14851  }
14852 
14853  if(Track->RouteFlashFlag && Display->ZoomOutFlag) // must have entered RouteFlash from normal screen so button states stored
14854  // dropped ZoomOutButton when route or point flashing, but leave this section in in case need to reinstate
14855  // no need to call Clearand... as that is called when revert to normal mode
14856  {
14857  if((Now - RouteFlashStartTime) >= TDateTime(RouteFlashDuration / 86400))
14858  {
14859  Track->RouteFlashFlag = false;
14860  if(PreferredRouteFlag)
14861  {
14863  }
14864  else
14865  {
14867  }
14868  ConstructRoute->ClearRoute(); // clear it immediately after use so as not to clutter the errorlog
14869  }
14870  }
14871 
14873  {
14874  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
14875  {
14876  // cancel if train is present on or enters a flashing point, either selected or diverging
14878  {
14880  Track->PointFlashFlag = false;
14882  Utilities->CallLogPop(76);
14883  return;
14884  }
14886  {
14888  Track->PointFlashFlag = false;
14890  Utilities->CallLogPop(77);
14891  return;
14892  }
14893 
14894  if(WarningFlash)
14895  {
14898  }
14899  else
14900  {
14902  }
14903  }
14904  else
14905  {
14910  {
14914  }
14916  Display->Update(); // resurrected when Update() dropped from PlotOutput etc
14917  Track->PointFlashFlag = false;
14919  }
14920  }
14921 
14923  // dropped ZoomOutButton when point flashing but leave this section in in case need to reinstate
14924  {
14925  if((Now - PointFlashStartTime) < TDateTime((PointsFlashDuration) / 86400))
14926  {
14930  {
14933  }
14934  Track->PointFlashFlag = false;
14936  }
14937  }
14938 // deal with level crossings
14939  if(!Track->ChangingLCVector.empty() && (Level2OperMode != Paused))
14940  {
14941  int H;
14942  int V;
14943  for(unsigned int x = 0; x < Track->ChangingLCVector.size(); x++)
14944  {
14945  H = Track->ChangingLCVector.at(x).HLoc;
14946  V = Track->ChangingLCVector.at(x).VLoc;
14947  if((Now - Track->ChangingLCVector.at(x).StartTime) < TDateTime((Track->ChangingLCVector.at(x).ChangeDuration) / 86400))
14948  // still flashing
14949  {
14950  if(WarningFlash)
14951  {
14952  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising) // closing to trains
14953  {
14954  Track->PlotRaisedLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
14955  }
14956  else
14957  {
14958  Track->PlotLoweredLinkedLevelCrossingBarriers(0, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
14959  Track->ChangingLCVector.at(x).ConsecSignals, Display);
14960  }
14961  }
14962  else
14963  {
14964  Track->PlotLCBaseElementsOnly(2, Track->ChangingLCVector.at(x).BarrierState, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
14965  Track->ChangingLCVector.at(x).ConsecSignals, Display);
14966  }
14967  }
14968  else
14969  // flashing period finished
14970  {
14971  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Raising)
14972  {
14973  Track->PlotRaisedLinkedLevelCrossingBarriers(2, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V, Display);
14974  Track->SetLinkedLevelCrossingBarrierAttributes(4, H, V, 0); // only set attr to 0 when fully raised
14975  // attributes set to 2 when changing state, now reset to 0, no other actions needed
14976  }
14977  else
14978  // barriers lowering
14979  {
14980  Track->PlotLoweredLinkedLevelCrossingBarriers(1, Track->ChangingLCVector.at(x).BaseElementSpeedTag, H, V,
14981  Track->ChangingLCVector.at(x).ConsecSignals, Display);
14982  Track->SetLinkedLevelCrossingBarrierAttributes(5, H, V, 1); // only set attr to 1 when fully lowered
14983  bool FoundFlag;
14984  int TVPos = Track->GetVectorPositionFromTrackMap(46, H, V, FoundFlag);
14985  if(!FoundFlag)
14986  {
14987  throw Exception("Failed to find a route at LC position HLoc = " + (AnsiString)H + " VLoc = " + (AnsiString)V);
14988  }
14989  int RouteNumber;
14990  AllRoutes->GetRouteTypeAndNumber(24, TVPos, 0, RouteNumber); // use 0 for LinkPos, could be 1 or 0 as only a single track element
14991  // don't need returned value of RouteType
14992  if(RouteNumber > -1) // if train crashed then there won't be a routenumber
14993  {
14994  AllRoutes->GetFixedRouteAt(196, RouteNumber).SetRouteSignals(8);
14995  }
14996  }
14997  }
14998  }
14999  for(int x = Track->ChangingLCVector.size() - 1; x >= 0; x--)
15000  // now transfer lowering barrier object from the ChangingLCVector to the BarriersDownVector, reset the start timer (to time the barrier down period)
15001  // and erase the object from the ChangingLCVector
15002  {
15003  if(!Track->IsLCBarrierFlashingAtHV(0, Track->ChangingLCVector.at(x).HLoc, Track->ChangingLCVector.at(x).VLoc))
15004  {
15005  if(Track->ChangingLCVector.at(x).BarrierState == TTrack::Lowering)
15006  {
15007  Track->ChangingLCVector.at(x).StartTime = TrainController->TTClockTime;
15008  Track->ChangingLCVector.at(x).BarrierState = TTrack::Down;
15009  Track->BarriersDownVector.push_back(Track->ChangingLCVector.at(x));
15010  }
15011  Track->ChangingLCVector.erase(Track->ChangingLCVector.begin() + x);
15012  }
15013  }
15014  }
15015  Utilities->CallLogPop(747);
15016 }
15017 
15018 // ---------------------------------------------------------------------------
15019 
15021  // set boundary, Home, NewHome, ZoomOut, CallingOn buttons & menu items as appropriate
15022 {
15023  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetSaveMenuAndButtons");
15024 
15025 // set save railway buttons
15026  bool SaveRailwayButtonsFlag = true;
15027 
15028  SaveRailwayTBPButton->Visible = true;
15029  SaveRailwayPDPButton->Visible = true;
15030  SaveSessionButton->Visible = true;
15031  if(Level1Mode == OperMode)
15032  {
15034  {
15035  SaveRailwayButtonsFlag = false;
15036  }
15037  // set PresetAutoSigRoutesButton enabled or not
15038  // enable if PreStart & no routes set
15039  if((Level2OperMode == PreStart) && (AllRoutes->AllRoutesVector.empty()))
15040  {
15041  PresetAutoSigRoutesButton->Enabled = true;
15042  }
15043  else
15044  {
15045  PresetAutoSigRoutesButton->Enabled = false;
15046  }
15047  }
15048  else
15049  {
15051  {
15052  SaveRailwayButtonsFlag = false;
15053  }
15054  else if(SavedFileName != "")
15055  {
15056  if((SavedFileName[SavedFileName.Length()] == 'y') || (SavedFileName[SavedFileName.Length()] == 'Y')) // 'rly' file
15057  {
15058  if(!(Track->IsReadyForOperation()))
15059  {
15060  SaveRailwayButtonsFlag = false; // can't save under its old name as not now a .rly file
15061  }
15062  }
15063  }
15064  }
15065  if(SaveRailwayButtonsFlag && (Level1Mode == BaseMode))
15066  {
15067  SaveRailwayBaseModeButton->Visible = true;
15068  }
15069  else
15070  {
15071  SaveRailwayBaseModeButton->Visible = false;
15072  }
15073  SaveRailwayTBPButton->Enabled = SaveRailwayButtonsFlag;
15074  SaveRailwayPDPButton->Enabled = SaveRailwayButtonsFlag;
15075  SaveRailwayBaseModeButton->Enabled = SaveRailwayButtonsFlag;
15076  SaveSessionButton->Enabled = SaveRailwayButtonsFlag;
15077 
15078 // set formatted timetable menu item
15079  if(TimetableTitle == "")
15080  {
15081  ExportTTMenuItem->Enabled = false;
15082  }
15083  else
15084  {
15085  ExportTTMenuItem->Enabled = true;
15086  }
15087 
15088 // set info menu items
15090  {
15091  FloatingInfoMenu->Enabled = false;
15092  TrackInfoMenuItem->Enabled = false;
15093  TrainInfoMenuItem->Enabled = false;
15094  }
15095  else
15096  {
15097  FloatingInfoMenu->Enabled = true;
15098  TrackInfoMenuItem->Enabled = true;
15099  if(Level1Mode == OperMode)
15100  {
15101  TrainInfoMenuItem->Enabled = true;
15102  }
15103  else
15104  {
15105  TrainInfoMenuItem->Enabled = false;
15106  }
15107  }
15108 
15109 // set all bar CallingOnButton operational to begin with - no, causes flickering of button graphics,
15110 // work on internal flags & then set buttons according to final flag values, then graphic won't change unless
15111 // there has been a legitimate change of state since the last access
15112 
15113  bool ZoomFlag = true, HomeFlag = true, NewHomeFlag = true, ScreenLeftFlag = true, ScreenRightFlag = true, ScreenUpFlag = true, ScreenDownFlag = true,
15114  TrackBuildPanelEnabledFlag = true, PrefDirPanelEnabledFlag = true, OperatingPanelEnabledFlag = true, TimetablePanelEnabledFlag = true;
15115 
15116  AnsiString TrackBuildPanelLabelCaptionStr = "Build/modify";
15117  AnsiString PrefDirPanelLabelCaptionStr = "Preferred direction selection";
15118  AnsiString OperatingPanelLabelCaptionStr = "Operation";
15119  AnsiString TimetablePanelLabelCaptionStr = "Timetable editor";
15120 
15121  if(!Display->ZoomOutFlag)
15122  { // prevent if half a screen or less visible (width = 60, height = 36) [Note HLocMin & Max 1 greater than extreme element]
15124  ScreenLeftFlag = false; // 60 - 30
15126  ScreenRightFlag = false; // 60 - (60 - 30)
15128  ScreenUpFlag = false; // 36 - 18
15130  ScreenDownFlag = false; // 36 - (36 - 18)
15131  }
15132  else
15133  { // prevent if less than a quarter of a screen visible (width = 240, height = 144)
15135  ScreenLeftFlag = false; // 240 - 60
15137  ScreenRightFlag = false; // 240 - (240 - 60)
15139  ScreenUpFlag = false; // 144 - 36
15141  ScreenDownFlag = false; // 144 - (144 - 36)
15142  }
15144  {
15145  ZoomFlag = false;
15146  HomeFlag = false;
15147  NewHomeFlag = false;
15148  ScreenLeftFlag = false;
15149  ScreenRightFlag = false;
15150  ScreenUpFlag = false;
15151  ScreenDownFlag = false;
15152  }
15153 
15154  if(Display->ZoomOutFlag)
15155  {
15156 // NewHomeFlag = false;
15157  TrackBuildPanelEnabledFlag = false;
15158  TrackBuildPanelLabelCaptionStr = "Disabled";
15159  PrefDirPanelEnabledFlag = false;
15160  PrefDirPanelLabelCaptionStr = "Disabled";
15161  OperatingPanelEnabledFlag = false;
15162  OperatingPanelLabelCaptionStr = "Disabled";
15163  TimetablePanelEnabledFlag = false;
15164  TimetablePanelLabelCaptionStr = "Disabled";
15165  }
15166 
15167  if(Level1Mode == OperMode)
15168  {
15169  if(Track->RouteFlashFlag || Track->PointFlashFlag || TTClockAdjPanel->Visible == true || TTClockAdjustWarningPanel->Visible == true) //TTClockAdjPanel added for v2.4.2 to keep it disabled after Clock2Stopped dropped
15170  {
15171  MTBFEditBox->Enabled = false;
15172  OperatingPanelEnabledFlag = false;
15173  OperatingPanelLabelCaptionStr = "Disabled";
15174  ZoomFlag = false;
15175  HomeFlag = false;
15176  NewHomeFlag = false;
15177  ScreenLeftFlag = false;
15178  ScreenRightFlag = false;
15179  ScreenUpFlag = false;
15180  ScreenDownFlag = false;
15181  SaveOperatingImageMenuItem->Enabled = false;
15182  }
15183  else
15184  {
15185  MTBFEditBox->Enabled = true;
15186  SaveOperatingImageMenuItem->Enabled = true;
15187  }
15188  }
15189 
15190  if(LocationNameTextBox->Visible)
15191  {
15192  ZoomFlag = false;
15193  HomeFlag = false;
15194  NewHomeFlag = false;
15195  ScreenLeftFlag = false;
15196  ScreenRightFlag = false;
15197  ScreenUpFlag = false;
15198  ScreenDownFlag = false;
15199  }
15200 
15201  if(TextBox->Visible) // added at v1.3.0 to prevent screen moving when movement keys pressed during text entry
15202  {
15203  ZoomFlag = false;
15204  HomeFlag = false;
15205  NewHomeFlag = false;
15206  ScreenLeftFlag = false;
15207  ScreenRightFlag = false;
15208  ScreenUpFlag = false;
15209  ScreenDownFlag = false;
15210  }
15211 
15212  if((Level1Mode == TimetableMode) && (TimetableEditPanel->Visible))
15213  // added at v1.3.0 to prevent screen moving when movement keys pressed during timetable compilation (allowed if TT hidden)
15214  {
15215  ZoomFlag = false;
15216  HomeFlag = false;
15217  NewHomeFlag = false;
15218  ScreenLeftFlag = false;
15219  ScreenRightFlag = false;
15220  ScreenUpFlag = false;
15221  ScreenDownFlag = false;
15222  }
15223 
15226  {
15227  ZoomFlag = false;
15228  }
15229 
15230  if(ZoomFlag)
15231  ZoomButton->Enabled = true;
15232  else
15233  ZoomButton->Enabled = false;
15234  if(HomeFlag)
15235  HomeButton->Enabled = true;
15236  else
15237  HomeButton->Enabled = false;
15238  if(NewHomeFlag)
15239  NewHomeButton->Enabled = true;
15240  else
15241  NewHomeButton->Enabled = false;
15242  if(ScreenLeftFlag)
15243  ScreenLeftButton->Enabled = true;
15244  else
15245  ScreenLeftButton->Enabled = false;
15246  if(ScreenRightFlag)
15247  ScreenRightButton->Enabled = true;
15248  else
15249  ScreenRightButton->Enabled = false;
15250  if(ScreenUpFlag)
15251  ScreenUpButton->Enabled = true;
15252  else
15253  ScreenUpButton->Enabled = false;
15254  if(ScreenDownFlag)
15255  ScreenDownButton->Enabled = true;
15256  else
15257  ScreenDownButton->Enabled = false;
15258  if(OperatingPanelEnabledFlag)
15259  OperatingPanel->Enabled = true;
15260  else
15261  OperatingPanel->Enabled = false;
15262  if(TrackBuildPanelEnabledFlag)
15263  TrackBuildPanel->Enabled = true;
15264  else
15265  TrackBuildPanel->Enabled = false;
15266  if(PrefDirPanelEnabledFlag)
15267  PrefDirPanel->Enabled = true;
15268  else
15269  PrefDirPanel->Enabled = false;
15270  if(TimetablePanelEnabledFlag)
15271  TimetablePanel->Enabled = true;
15272  else
15273  TimetablePanel->Enabled = false;
15274  TrackBuildPanelLabel->Caption = TrackBuildPanelLabelCaptionStr;
15275  PrefDirPanelLabel->Caption = PrefDirPanelLabelCaptionStr;
15276  OperatingPanelLabel->Caption = OperatingPanelLabelCaptionStr;
15277  TimetablePanelLabel->Caption = TimetablePanelLabelCaptionStr;
15278 
15279 // check if any CallingOnFlags set & set button accordingly
15280  if(Display->ZoomOutFlag)
15281  {
15282  CallingOnButton->Enabled = false;
15283  CallingOnButton->Down = false;
15284  }
15285  else
15286  {
15287  if(Level2OperMode == Operating)
15288  {
15289  bool CallOnValid = false;
15290  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
15291  {
15293  {
15294  CallingOnButton->Enabled = true;
15295  CallOnValid = true;
15296  }
15297  }
15298  if(!CallOnValid)
15299  {
15300  CallingOnButton->Enabled = false;
15301  CallingOnButton->Down = false;
15302  }
15303  }
15304  else
15305  {
15306  CallingOnButton->Enabled = false;
15307  CallingOnButton->Down = false;
15308  }
15309  }
15310  Utilities->CallLogPop(970);
15311 }
15312 
15313 // ---------------------------------------------------------------------------
15314 
15315 void TInterface::ErrorLog(int Caller, AnsiString Message)
15316 {
15317 // create an error file for diagnostic purposes called on detection of a runtime error
15318 
15319 // Note: For faults in ClockTimer2, after the catch block in ClockTimer2 which calls this function, execution continues from where
15320 // ClockTimer2 was called, so the Utilities->Clock2Stopped flag is cleared and the whole sequence repeats itself, including the fault, until
15321 // the user presses the Exit button. Note also that Utilities->CallLogPop, called when ClockTimer (not ClockTimer2) returns, pops the error
15322 // message off the back of the Utilities->CallLog, not the ClockTimer call. Hence entries keep stacking up, including the push_front entry
15323 // but not the push_back error entry, and when finally printed there is a whole series of entries for the one fault, the number
15324 // depending on the time taken to press Exit.
15325 // Hence introduce an ErrorLogCalledFlag, set to true on first call, and preventing further calls thereafter.
15326 
15327  if(ErrorLogCalledFlag)
15328  return;
15329 
15330  ErrorLogCalledFlag = true;
15331  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + "," + Message);
15332  Utilities->CallLog.push_front("Version: " + ProgramVersion + "; Time and date: " + Utilities->DateTimeStamp());
15333  SaveErrorFile();
15334  if((TempTTFileName != "") && FileExists(TempTTFileName))
15335  {
15336  DeleteFile(TempTTFileName);
15337  }
15338  Display->GetImage()->Visible = false;
15339  PerformancePanel->Visible = false;
15340  OperatorActionPanel->Visible = false; // new v2.2.0
15341  TrackBuildPanel->Visible = false;
15342  TrackElementPanel->Visible = false;
15343  LocationNameTextBox->Visible = false;
15344  TextBox->Visible = false;
15345  TrackLengthPanel->Visible = false;
15346  InfoPanel->Visible = false;
15347  PrefDirPanel->Visible = false;
15348  TimetablePanel->Visible = false;
15349  TimetableEditPanel->Visible = false;
15350  OperatingPanel->Visible = false;
15351  FloatingPanel->Visible = false;
15352  ModeMenu->Enabled = false;
15353  SigImagePanel->Visible = false; // new at v2.3.0
15354  FileMenu->Enabled = false;
15355  EditMenu->Enabled = false;
15356  FloatingInfoMenu->Enabled = false;
15357  HelpMenu->Enabled = false;
15358 // SaveHeaderMenu1->Enabled = false;
15359  ScreenLeftButton->Visible = false;
15360  ScreenRightButton->Visible = false;
15361  ScreenUpButton->Visible = false;
15362  ScreenDownButton->Visible = false;
15363  HomeButton->Visible = false;
15364  NewHomeButton->Visible = false;
15365  ZoomButton->Visible = false;
15366  PrefDirKey->Visible = false;
15367  DistanceKey->Visible = false;
15368  OutputLog1->Caption = "";
15369  OutputLog2->Caption = "";
15370  OutputLog3->Caption = "";
15371  OutputLog4->Caption = "";
15372  OutputLog5->Caption = "";
15373  OutputLog6->Caption = "";
15374  OutputLog7->Caption = "";
15375  OutputLog8->Caption = "";
15376  OutputLog9->Caption = "";
15377  OutputLog10->Caption = "";
15378  if(Caller == 113)
15379  {
15380  ErrorMessageStoreImage->Visible = true;
15381  }
15382  else
15383  {
15384  ErrorMessage->Visible = true;
15385  }
15386  ErrorButton->Visible = true;
15387  Screen->Cursor = TCursor(-2); // Arrow; - in case was an hourglass
15388 // No need for Utilities->CallLogPop as the call log deque has already been written to file & the next action
15389 // is to close the program when the exit button is pressed
15390 }
15391 
15392 // ---------------------------------------------------------------------------
15393 
15395  // not used from v2.2.0 as now allow floating panel & label to overlie performance panel
15396 {
15397  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPerformancePanelObscuringFloatingLabel");
15398  if(FloatingPanel->Visible == false)
15399  {
15400  Utilities->CallLogPop(1205);
15401  return false;
15402  }
15403 // pptop >= flbot, ppbot <= fltop, ppleft >= flright, ppright <= flleft
15404  if((PerformancePanel->Top >= (FloatingPanel->Top + FloatingPanel->Height)) || ((PerformancePanel->Top + PerformancePanel->Height) <= FloatingPanel->Top) ||
15405  (PerformancePanel->Left >= (FloatingPanel->Left + FloatingPanel->Width)) || ((PerformancePanel->Left + PerformancePanel->Width) <= FloatingPanel->Left))
15406  {
15407  Utilities->CallLogPop(1206);
15408  return false;
15409  }
15410  else
15411  {
15412  Utilities->CallLogPop(1207);
15413  return true;
15414  }
15415 }
15416 // ---------------------------------------------------------------------------
15417 
15418 void TInterface::SetCaption(int Caller)
15419 {
15420 /*
15421  NamedRailway; RlyFile; NamedTimetable
15422  n x x "New railway under development";
15423  y n x RailwayTitle + ": under development";
15424  y y n RailwayTitle + ": no timetable loaded";
15425  y y y RailwayTitle + ", " + TimetableTitle;
15426 */
15427 
15428  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetCaption");
15429  if(RailwayTitle == "")
15430  Caption = "Railway: New railway under development";
15431  else if(!RlyFile)
15432  Caption = "Railway: " + RailwayTitle + " under development";
15433 // else if(TimetableTitle == "") Caption = "Railway: " + RailwayTitle + "; Timetable: none loaded";
15434  else if(TimetableTitle == "")
15435  Caption = "Railway: " + RailwayTitle; // changed at v2.1.0, no need to mention TT if none loaded
15436  else
15437  Caption = "Railway: " + RailwayTitle + "; Timetable: " + TimetableTitle;
15438  Utilities->CallLogPop(1208);
15439 }
15440 
15441 // ---------------------------------------------------------------------------
15442 
15443 void TInterface::ResetAll(int Caller)
15444 {
15445  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAll");
15446  LastNonCtrlOrShiftKeyDown = -1; // added at v2.4.2 to no key down
15448  Track->GapFlashRedPosition = -1;
15449  Track->GapFlashFlag = false;
15450  Track->RouteFlashFlag = false;
15451  Track->PointFlashFlag = false;
15453  AutoSigsFlag = false;
15454  PreventGapOffsetResetting = false;
15455 
15456  Utilities->Clock2Stopped = false;
15457  TTClockSpeed = 1;
15458  TTClockSpeedLabel->Caption = "x1";
15459  Track->SetTrackFinished(false);
15461  CurrentSpeedButton = 0; // not assigned yet
15463  StartX = 0;
15464  StartY = 0;
15465  mbLeftDown = false;
15467  TextOrUserGraphicGridButton->Glyph->LoadFromResourceName(0, "PixelPrecision1");
15469  SigAspectButton->Glyph->LoadFromResourceName(0, "FourAspect");
15471  WarningFlashCount = 0;
15472 
15473  Level1Mode = BaseMode;
15474  SetLevel1Mode(26);
15475  RouteMode = None;
15476  PreferredRoute = true;
15477  ConsecSignalsRoute = true;
15478  DevelopmentPanel->Visible = false;
15479 
15480  MainScreen->Canvas->CopyMode = cmSrcCopy;
15481  FloatingPanel->Visible = false;
15482  OverallDistance = 0;
15483  OverallSpeedLimit = -1;
15484  AllRoutes->RouteTruncateFlag = false;
15485  CallingOnButton->Down = false;
15486  Display->ZoomOutFlag = false;
15487  ScreenGridFlag = false;
15488  InfoCaptionStore = "";
15489  ErrorLogCalledFlag = false;
15490  ErrorMessage->Visible = false;
15491  ErrorMessageStoreImage->Visible = false;
15492  TempCursorSet = false;
15493  TempCursor = TCursor(-2); // Arrow
15494  WholeRailwayMoving = false; // new at v2.1.0
15495 
15496  TrainController->TTClockTime = TDateTime(0); // default setting
15497  TTClockAdjPanel->Visible = false;
15499  ConflictPanel->Visible = false;
15500  SelectedTrainID = -1;
15501  SetTrackBuildImages(11);
15502 // TrackInfoOnOffMenuItem->Caption = "Show"; dropped these here at v1.2.0 so don't reset when load a session file
15503 // TrainStatusInfoOnOffMenuItem->Caption = "Show Status";
15504 // TrainTTInfoOnOffMenuItem->Caption = "Show Timetable";
15505  Track->CalcHLocMinEtc(8);
15506  FileChangedFlag = false;
15507  RlyFile = false;
15508  SaveSessionFlag = false;
15509  LoadSessionFlag = false;
15510  SelectionValid = false;
15511  TimetableChangedFlag = false;
15512  SavedFileName = "";
15513  RailwayTitle = "";
15514  TimetableTitle = "";
15515  SetCaption(1);
15516  CreateEditTTFileName = ""; // set to null to allow a check during error file saving, if not null save the tt being edited to the file
15517  // added for Beta v0.2b
15518  CreateEditTTTitle = ""; // as above
15519  AllRoutes->NextRouteID = 0;
15520  TTrain::NextTrainID = 0; // reset to 0 whenever enter operating mode
15521  TFont *TempFont = new TFont; // if try to alter MainScreen->Canvas->Font directly it won't change the style for some reason
15522 
15523  TempFont->Style.Clear();
15524  TempFont->Name = "MS Sans Serif"; // reset font, else stays set to last displayed text font
15525  TempFont->Size = 10;
15526  TempFont->Color = clB0G0R0;
15527  TempFont->Charset = (TFontCharset)(0);
15528  MainScreen->Canvas->Font->Assign(TempFont);
15529  PerformancePanel->Top = MainScreen->Top + MainScreen->Height - PerformancePanel->Height;
15530  PerformancePanel->Left = MainScreen->Left;
15531  OperatorActionPanel->Top = MainScreen->Top + MainScreen->Height - OperatorActionPanel->Height; // new v2.2.0
15532  OperatorActionPanel->Left = MainScreen->Left + MainScreen->Width - OperatorActionPanel->Width; ; // new v2.2.0
15533  // ScreenRightButton->Left = MainScreen->Width + MainScreen->Left; //Button values changed at v2.1.0 to allow for screen resizing
15534  // ScreenLeftButton->Left = ScreenRightButton->Left;
15535  // ScreenUpButton->Left = ScreenRightButton->Left;
15536  // ScreenDownButton->Left = ScreenRightButton->Left;
15537  // HomeButton->Left = ScreenRightButton->Left;
15538  // NewHomeButton->Left = ScreenRightButton->Left;
15539  // ZoomButton->Left = ScreenRightButton->Left;
15540  DevelopmentPanel->Top = MainScreen->Top + MainScreen->Height - DevelopmentPanel->Height;
15541  DevelopmentPanel->Left = MainScreen->Left + MainScreen->Width - DevelopmentPanel->Width; ; // new v2.2.0
15542 
15543  delete TempFont;
15544  CtrlKey = false;
15545  ShiftKey = false;
15546  Utilities->CallLogPop(1209);
15547 }
15548 
15549 // ---------------------------------------------------------------------------
15550 
15552 {
15553  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrackBuildImages,");
15554  if((Level1Mode == OperMode) || RlyFile)
15555  {
15556  TrackLinkedImage->Visible = false;
15557  TrackNotLinkedImage->Visible = false;
15558  GapsSetImage->Visible = false;
15559  GapsNotSetImage->Visible = false;
15560  LocationNamesSetImage->Visible = false;
15561  LocationNamesNotSetImage->Visible = false;
15562  Utilities->CallLogPop(1114);
15563  return;
15564  }
15565  else
15566  {
15567  if(!Track->NoActiveTrack(9))
15568  {
15569  if(Track->IsTrackFinished())
15570  {
15571  TrackLinkedImage->Visible = true;
15572  TrackNotLinkedImage->Visible = false;
15573  }
15574  else
15575  {
15576  TrackNotLinkedImage->Visible = true;
15577  TrackLinkedImage->Visible = false;
15578  }
15579  }
15580  else
15581  {
15582  TrackLinkedImage->Visible = false;
15583  TrackNotLinkedImage->Visible = false;
15584  }
15585 
15586  if(!Track->NoGaps(1))
15587  {
15588  if(Track->GapsUnset(6))
15589  {
15590  GapsNotSetImage->Visible = true;
15591  GapsSetImage->Visible = false;
15592  }
15593  else
15594  {
15595  GapsNotSetImage->Visible = false;
15596  GapsSetImage->Visible = true;
15597  }
15598  }
15599  else
15600  {
15601  GapsNotSetImage->Visible = false;
15602  GapsSetImage->Visible = false;
15603  }
15604 
15606  {
15607  if(Track->LocationsNotNamed(0))
15608  {
15609  LocationNamesSetImage->Visible = false;
15610  LocationNamesNotSetImage->Visible = true;
15611  }
15612  else
15613  {
15614  LocationNamesSetImage->Visible = true;
15615  LocationNamesNotSetImage->Visible = false;
15616  }
15617  }
15618  else
15619  {
15620  LocationNamesSetImage->Visible = false;
15621  LocationNamesNotSetImage->Visible = false;
15622  }
15623  }
15624  Utilities->CallLogPop(1113);
15625 }
15626 
15627 // ---------------------------------------------------------------------------
15628 
15629 void TInterface::ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
15630 {
15631  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetChangedFileDataAndCaption");
15632  FileChangedFlag = true;
15633  if(NonPrefDirChangesMade)
15634  {
15635  if(RlyFile) // i.e. was a Railway file but major changes made so class as a new railway
15636  {
15637  RailwayTitle = "";
15638  TimetableTitle = "";
15639  SavedFileName = "";
15640  RlyFile = false;
15641  }
15642  TimetableTitle = ""; // should have been reset already during user mode change but include here also
15643  SetTrackBuildImages(15);
15644  }
15645  SetCaption(2);
15646  Utilities->CallLogPop(1210);
15647 }
15648 
15649 // ---------------------------------------------------------------------------
15650 
15651 void TInterface::SaveSession(int Caller)
15652 { // ExcessLCDownMins saved as string after ***Interface*** see below
15653  try
15654  {
15655  TrainController->LogEvent("SaveSession");
15656  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSession");
15657  AnsiString CurrentDateTimeStr = "", TimetableTimeStr = "", SessionFileStr = "";
15658  Screen->Cursor = TCursor(-11); // Hourglass;
15659  CurrentDateTimeStr = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
15660  // avoid characters in filename:= / \ : * ? " < > |
15661  TimetableTimeStr = Utilities->Format96HHMMSS(TrainController->TTClockTime);
15662  TimetableTimeStr = TimetableTimeStr.SubString(1, 2) + '.' + TimetableTimeStr.SubString(4, 2) + '.' + TimetableTimeStr.SubString(7, 2);
15663  SessionFileStr = CurDir + "\\" + SESSION_DIR_NAME + "\\Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " + RailwayTitle +
15664  "; " + TimetableTitle + ".ssn";
15665  std::ofstream SessionFile(SessionFileStr.c_str());
15666  if(!(SessionFile.fail()))
15667  {
15668  Utilities->SaveFileString(SessionFile, ProgramVersion + ": ***Interface***" + FloatToStr(TrainController->ExcessLCDownMins));
15669 // added ExcessLC... at v2.2.0 as omitted earlier
15670  SaveInterface(0, SessionFile);
15671  // save track elements
15672  Utilities->SaveFileString(SessionFile, "***Track***");
15673  if(Track->UserGraphicVector.empty())
15674  {
15675  Track->SaveTrack(4, SessionFile, false); // false for no graphics (**Active elements** saved as marker)
15676  }
15677  else
15678  {
15679  Track->SaveTrack(11, SessionFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
15680  }
15681  // save text elements
15682  Utilities->SaveFileString(SessionFile, "***Text***");
15683  TextHandler->SaveText(2, SessionFile);
15684  // save PrefDir elements
15685  Utilities->SaveFileString(SessionFile, "***PrefDirs***");
15686  EveryPrefDir->SavePrefDirVector(2, SessionFile);
15687  if(!Track->UserGraphicVector.empty())
15688  {
15689  // save user graphics
15690  Track->SaveUserGraphics(2, SessionFile);
15691  }
15692  // save routes
15693  Utilities->SaveFileString(SessionFile, "***Routes***");
15694  AllRoutes->SaveRoutes(0, SessionFile);
15695  // save LockedRoutes
15696  Utilities->SaveFileString(SessionFile, "***Locked routes***");
15697  TrainController->SaveSessionLockedRoutes(0, SessionFile);
15698  // save ContinuationAutoSigEntries
15699  Utilities->SaveFileString(SessionFile, "***ContinuationAutoSigEntries***");
15701  // save BarriersDownVector
15702  Utilities->SaveFileString(SessionFile, "***BarriersDownVector***");
15703  Track->SaveSessionBarriersDownVector(0, SessionFile);
15704  // save timetable
15705  Utilities->SaveFileString(SessionFile, "***Timetable***");
15706  if(!(SaveTimetableToSessionFile(0, SessionFile, SessionFileStr)))
15707  {
15708  SessionFile.close();
15709  DeleteFile(SessionFileStr);
15710  Screen->Cursor = TCursor(-2); // Arrow;
15711  TrainController->StopTTClockMessage(3, "Error saving file, unable to save session");
15712  Utilities->CallLogPop(1150);
15713  return;
15714  }
15715  // save TimetableClock
15716  Utilities->SaveFileString(SessionFile, "***TimetableClock***");
15717  Utilities->SaveFileDouble(SessionFile, double(TrainController->TTClockTime));
15718 
15719  // save trains
15720  Utilities->SaveFileString(SessionFile, "***Trains***");
15721  TrainController->SaveSessionTrains(0, SessionFile);
15722  // save performance file
15723  Utilities->SaveFileString(SessionFile, "***Performance file***");
15724  SavePerformanceFile(0, SessionFile);
15725  Utilities->SaveFileString(SessionFile, "***End of performance file***");
15726 // addition at v2.4.0 to save TrainController->AvHoursIntValue + any future additions
15727  Utilities->SaveFileString(SessionFile, "***Additions after v2.3.1***");
15730  Utilities->SaveFileString(SessionFile, "***Failed Trains***");
15731  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
15732  {
15734  {
15737  }
15738  }
15739  Utilities->SaveFileInt(SessionFile, -1); // marker for end of failed trains
15740  Utilities->SaveFileString(SessionFile, "End of file at v2.4.0");
15741 // end of v2.4.0 addition
15742  SessionFile.close();
15743  TrainController->StopTTClockMessage(4, "Session saved: Session " + CurrentDateTimeStr + "; Timetable time " + TimetableTimeStr + "; " +
15744  RailwayTitle + "; " + TimetableTitle + ".ssn");
15745  LastNonCtrlOrShiftKeyDown = -1; //to restore the ability to reselect Ctrl S after a save (FormKeyUp doesn't work because the Interface form doesn't have focus)
15746  }
15747  else
15748  {
15749  TrainController->StopTTClockMessage(5, "Session file failed to open, session not saved. Ensure that there is a folder named " + SESSION_DIR_NAME +
15750  " in the folder where the 'Railway.exe' program file resides");
15751  }
15752  Screen->Cursor = TCursor(-2); // Arrow
15753  Utilities->CallLogPop(1141);
15754  }
15755  catch(const Exception &e)
15756  {
15757  ErrorLog(40, e.Message);
15758  }
15759 }
15760 
15761 // ---------------------------------------------------------------------------
15762 
15763 void TInterface::LoadSession(int Caller)
15764  // always loads in 'Paused' or 'PreStart' mode
15765 {
15766 // remember to load the timetable clock
15767 // no routes in build
15768 // prob need to set 'OperMode' then 'Paused', ensure have all info needed for these
15769 // set buttons enabled to correspond to flags on reloading. If no PrefDirs then disable all route buttons
15770 // set RlyFile true
15771  try
15772  {
15773  TrainController->LogEvent("LoadSession");
15774  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadSession");
15775  if(!ClearEverything(4))
15776  {
15777  Utilities->CallLogPop(1145);
15778  return;
15779  }
15780  LoadSessionDialog->Filter = "Session file (*.ssn)|*.ssn";
15781  if(LoadSessionDialog->Execute())
15782  {
15783  TrainController->LogEvent("LoadSession " + LoadSessionDialog->FileName);
15784  Screen->Cursor = TCursor(-11); // Hourglass;
15785  if(SessionFileIntegrityCheck(0, AnsiString(LoadSessionDialog->FileName).c_str()))
15786  // if(true)
15787  {
15788  std::ifstream SessionFile(AnsiString(LoadSessionDialog->FileName).c_str());
15789  if(!(SessionFile.fail()))
15790  {
15791  TrainController->AvHoursIntValue = 0; // initial value set at v2.4.0 in case not changed later
15792  TrainController->MTBFHours = 0; // initial value set at v2.4.0 in case not changed later
15793  AnsiString TempString = Utilities->LoadFileString(SessionFile);
15794 // "version + : ***Interface***" + at v2.2.0 ExcessLCDownMins (omitted earlier)
15795 
15796  int LastCharBeforeFloat = TempString.LastDelimiter('*'); // added at v2.2.0
15797  if((LastCharBeforeFloat == 0) || (LastCharBeforeFloat == TempString.Length()))
15798  // can't find it or no value for Excess LCDownMins, either way count as zero
15799  {
15801  }
15802  else
15803  {
15804  AnsiString FloatStr = TempString.SubString(LastCharBeforeFloat + 1, TempString.Length() - LastCharBeforeFloat);
15805  if(!Utilities->CheckStringDouble(FloatStr)) // returns false for empty string or invalid double
15806  {
15808  }
15809  else
15810  {
15811  TrainController->ExcessLCDownMins = FloatStr.ToDouble();
15812  }
15813  } // end of v2.2.0 * v2.4.0 additions
15814 
15815  LoadInterface(0, SessionFile);
15816  int TempDisplayOffsetH = Display->DisplayOffsetH; // stored as they are zeroed when track loaded
15817  int TempDisplayOffsetV = Display->DisplayOffsetV;
15818  int TempDisplayOffsetHHome = Display->DisplayOffsetHHome;
15819  int TempDisplayOffsetVHome = Display->DisplayOffsetVHome;
15820  bool GraphicsFollow = false;
15821  // load track elements
15822  TempString = Utilities->LoadFileString(SessionFile); // ***Track***"
15823  Track->LoadTrack(4, SessionFile, GraphicsFollow);
15824  // load text elements
15825  TempString = Utilities->LoadFileString(SessionFile); // ***Text***"
15826  TextHandler->LoadText(1, SessionFile);
15827  // load PrefDir elements
15828  TempString = Utilities->LoadFileString(SessionFile); // "***PrefDirs***"
15829  EveryPrefDir->LoadPrefDir(1, SessionFile);
15830  if(GraphicsFollow)
15831  {
15832  Track->LoadGraphics(1, SessionFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME); // include path to Graphics folder);
15833  }
15835  {
15836  SessionFile.close();
15837  Screen->Cursor = TCursor(-2); // Arrow;
15838  ShowMessage("Corruption in preferred direction section of the session file, session can't be loaded");
15839  Utilities->CallLogPop(1438);
15840  return;
15841  }
15842  // load routes
15843  TempString = Utilities->LoadFileString(SessionFile); // "***Routes***"
15844  if(!AllRoutes->LoadRoutes(0, SessionFile))
15845  {
15846  SessionFile.close();
15847  Screen->Cursor = TCursor(-2); // Arrow;
15848  ShowMessage("Corruption in route section of the session file, session can't be loaded");
15849  Utilities->CallLogPop(1439);
15850  return;
15851  }
15852  // load LockedRoutes
15853  TempString = Utilities->LoadFileString(SessionFile); // "***Locked routes***"
15854  TrainController->LoadSessionLockedRoutes(0, SessionFile);
15855  // load ContinuationAutoSigEntries
15856  TempString = Utilities->LoadFileString(SessionFile); // "***ContinuationAutoSigEntries***"
15858  // load BarriersDownVector if present, but ensure backwards compatibility with earlier files
15859  TempString = Utilities->LoadFileString(SessionFile); // "***BarriersDownVector***" or "***Timetable***"
15860  if(TempString == "***BarriersDownVector***")
15861  {
15862  Track->LoadBarriersDownVector(0, SessionFile);
15863  TempString = Utilities->LoadFileString(SessionFile); // "***Timetable***"
15864  }
15865  // load timetable (marker "***Timetable***" already loaded)
15866  if(!(LoadTimetableFromSessionFile(0, SessionFile)))
15867  {
15868  SessionFile.close();
15869  Screen->Cursor = TCursor(-2); // Arrow;
15870  ShowMessage("Unable to load timetable section of the session file, session can't be loaded");
15871  Utilities->CallLogPop(1151);
15872  return;
15873  }
15874  // TimetableTitle should be loaded at this stage - check
15875  if(TimetableTitle == "")
15876  {
15877  SessionFile.close();
15878  Screen->Cursor = TCursor(-2); // Arrow;
15879  throw Exception("TimetableTitle null in LoadSession");
15880  }
15881  // load timetable clock
15882  TempString = Utilities->LoadFileString(SessionFile); // ***TimetableClock***
15883  TrainController->RestartTime = TDateTime(Utilities->LoadFileDouble(SessionFile)); // ClockTime set in RestartSessionOperMode;
15884  // load trains
15885  TempString = Utilities->LoadFileString(SessionFile); // ***Trains***
15886  TrainController->LoadSessionTrains(0, SessionFile);
15887  // load performance file + populate the performance log
15888  TempString = Utilities->LoadFileString(SessionFile); // ***Performance file***
15889  // first reset the performance file name and open it before reloading it
15890  PerformanceFileName = TDateTime::CurrentDateTime().FormatString("dd-mm-yyyy hh.nn.ss");
15891  // avoid characters in filename:= / \ : * ? " < > |
15892  PerformanceFileName = CurDir + "\\" + PERFLOG_DIR_NAME + "\\Log " + PerformanceFileName + "; " + RailwayTitle + "; " +
15893  TimetableTitle + ".txt";
15894  Utilities->PerformanceFile.open(PerformanceFileName.c_str(), std::ios_base::out);
15895  if(Utilities->PerformanceFile.fail())
15896  {
15897  ShowMessage("Performance logfile failed to open, logs won't be saved. Ensure that there is a folder named " + PERFLOG_DIR_NAME +
15898  " in the folder where the 'Railway.exe' program file resides");
15899  }
15900  // now reload the performance file
15901  LoadPerformanceFile(0, SessionFile);
15902  // addition at v2.4.0
15903  char TempChar;
15904  SessionFile.get(TempChar);
15905  while(!SessionFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
15906  {
15907  SessionFile.get(TempChar);
15908  }
15909  if(SessionFile.eof()) // end of file
15910  {
15913  SessionFile.close(); // no TrainController->AvHoursIntValue & no failed trains
15914  }
15915  else
15916  {
15917  AnsiString DummyStr = Utilities->LoadFileString(SessionFile); // "**Additions after v2.3.1***" discarded (first '*' loaded earlier)
15918  TrainController->AvHoursIntValue = Utilities->LoadFileInt(SessionFile); // TrainController->AvHoursIntValue added at v2.4.0
15919  TrainController->NumFailures = Utilities->LoadFileInt(SessionFile); // number of train failures
15920  TrainController->MTBFHours = TrainController->AvHoursIntValue; // TTClockSpeed set to 1 in RestartSessionMode so no need to include here
15921  // now load any failed trains along with their OriginalPowerAtRail values
15922  DummyStr = Utilities->LoadFileString(SessionFile); // discard "***Failed Trains***"
15923  int ID = Utilities->LoadFileInt(SessionFile); // train ID or -1 for no more failed trains
15924  double PowerDouble;
15925  while(ID != -1)
15926  {
15927  PowerDouble = Utilities->LoadFileDouble(SessionFile); // ok TrainVector loaded at this stage (loaded in LoadSessionTrains)
15930  ID = Utilities->LoadFileInt(SessionFile);
15931  }
15932  SessionFile.close();
15933  }
15934  // deal with other settings
15935  Display->DisplayOffsetH = TempDisplayOffsetH; // reset to saved values
15936  Display->DisplayOffsetV = TempDisplayOffsetV;
15937  Display->DisplayOffsetHHome = TempDisplayOffsetHHome;
15938  Display->DisplayOffsetVHome = TempDisplayOffsetVHome;
15939  // now set attributes to 1 for all LCs with barriers down
15940  for(unsigned int x = 0; x < Track->BarriersDownVector.size(); x++)
15941  {
15943  }
15944  Track->ChangingLCVector.clear();
15945  Track->CalcHLocMinEtc(10);
15947  SetLevel1Mode(27);
15948  if(Level2OperMode == PreStart)
15949  // this section added at v1.3.2 as otherwise only in MainScreenMouseDown2, and if load a session without clicking mouse on screen
15950  { // then delay unspecified though seems to be 0
15951  PointsFlashDuration = 0.0;
15954  }
15955  else
15956  {
15960  }
15961  RlyFile = true;
15962  SetCaption(3);
15964  }
15965  }
15966  else
15967  {
15968  ShowMessage("Session file integrity check failed, unable to load session.");
15969  }
15970  Screen->Cursor = TCursor(-2); // Arrow;
15971  }
15972  Utilities->CallLogPop(1146);
15973  }
15974  catch(const Exception &e)
15975  {
15976  if((e.Message.Pos("esource") > 0) || (e.Message.Pos("arameter") > 0)) // 'Resource or Parameter, avoid capitals as may be OS dependent
15977  {
15978  Screen->Cursor = TCursor(-2); // Arrow;
15979  OutputLog1->Caption = "";
15980  OutputLog2->Caption = "";
15981  OutputLog3->Caption = "";
15982  OutputLog4->Caption = "";
15983  OutputLog5->Caption = "";
15984  OutputLog6->Caption = "";
15985  OutputLog7->Caption = "";
15986  OutputLog8->Caption = "";
15987  OutputLog9->Caption = "";
15988  OutputLog10->Caption = "";
15989  UnicodeString MessageStr =
15990  "Insufficient memory available to load the file, and partial load likely to be corrupt. Application will terminate. Try loading the session as the first action after reloading the program.";
15991 // UnicodeString MessageStr = "Last train loaded = " + UnicodeString(TrainController->LastTrainLoaded); //for debugging session train loading for many trains
15992  Application->MessageBox(MessageStr.c_str(), L"Out of memory", MB_OK | MB_ICONERROR);
15993  Application->Terminate();
15994  }
15995  else
15996  {
15997  ErrorLog(41, e.Message);
15998  }
15999  }
16000 }
16001 
16002 // ---------------------------------------------------------------------------
16003 
16004 void TInterface::SaveInterface(int Caller, std::ofstream &SessionFile)
16005 {
16006  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveInterface");
16007  if(Level2OperMode == PreStart)
16008  Utilities->SaveFileString(SessionFile, AnsiString("PreStart"));
16009  else
16010  Utilities->SaveFileString(SessionFile, AnsiString("NotPreStart")); // covers both Paused & Operating
16011  Utilities->SaveFileString(SessionFile, RailwayTitle);
16012  Utilities->SaveFileString(SessionFile, TimetableTitle);
16013  Utilities->SaveFileBool(SessionFile, PreferredRoute);
16014  Utilities->SaveFileBool(SessionFile, ConsecSignalsRoute);
16015  Utilities->SaveFileBool(SessionFile, AutoSigsFlag);
16016  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetH);
16017  Utilities->SaveFileInt(SessionFile, Display->DisplayOffsetV);
16022  Utilities->SaveFileString(SessionFile, OutputLog1->Caption);
16023  Utilities->SaveFileString(SessionFile, OutputLog2->Caption);
16024  Utilities->SaveFileString(SessionFile, OutputLog3->Caption);
16025  Utilities->SaveFileString(SessionFile, OutputLog4->Caption);
16026  Utilities->SaveFileString(SessionFile, OutputLog5->Caption);
16027  Utilities->SaveFileString(SessionFile, OutputLog6->Caption);
16028  Utilities->SaveFileString(SessionFile, OutputLog7->Caption);
16029  Utilities->SaveFileString(SessionFile, OutputLog8->Caption);
16030  Utilities->SaveFileString(SessionFile, OutputLog9->Caption);
16031  Utilities->SaveFileString(SessionFile, OutputLog10->Caption);
16032 
16054  // ExcessLCDownMins saved after ***Interface*** at v2.2.0 (omitted in error earlier)
16055  Utilities->CallLogPop(1211);
16056 }
16057 
16058 // ---------------------------------------------------------------------------
16059 void TInterface::LoadInterface(int Caller, std::ifstream &SessionFile)
16060 {
16061  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadInterface");
16062  AnsiString OpMode = Utilities->LoadFileString(SessionFile);
16063 
16064  if(OpMode == "PreStart")
16066  else
16068  RailwayTitle = Utilities->LoadFileString(SessionFile);
16069  SavedFileName = CurDir + "\\" + RAILWAY_DIR_NAME + "\\" + RailwayTitle + ".rly";
16070 
16071  TimetableTitle = Utilities->LoadFileString(SessionFile);
16072  PreferredRoute = Utilities->LoadFileBool(SessionFile);
16073  ConsecSignalsRoute = Utilities->LoadFileBool(SessionFile);
16074  AutoSigsFlag = Utilities->LoadFileBool(SessionFile);
16075  Display->DisplayOffsetH = Utilities->LoadFileInt(SessionFile);
16076  Display->DisplayOffsetV = Utilities->LoadFileInt(SessionFile);
16081  OutputLog1->Caption = Utilities->LoadFileString(SessionFile);
16082  OutputLog2->Caption = Utilities->LoadFileString(SessionFile);
16083  OutputLog3->Caption = Utilities->LoadFileString(SessionFile);
16084  OutputLog4->Caption = Utilities->LoadFileString(SessionFile);
16085  OutputLog5->Caption = Utilities->LoadFileString(SessionFile);
16086  OutputLog6->Caption = Utilities->LoadFileString(SessionFile);
16087  OutputLog7->Caption = Utilities->LoadFileString(SessionFile);
16088  OutputLog8->Caption = Utilities->LoadFileString(SessionFile);
16089  OutputLog9->Caption = Utilities->LoadFileString(SessionFile);
16090  OutputLog10->Caption = Utilities->LoadFileString(SessionFile);
16091 
16099  TrainController->LateDeps = Utilities->LoadFileInt(SessionFile);
16113  Utilities->CallLogPop(1212);
16114 }
16115 
16116 // ---------------------------------------------------------------------------
16117 
16118 bool TInterface::CheckInterface(int Caller, std::ifstream &SessionFile)
16119 {
16120  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckInterface");
16121 
16122  AnsiString OpMode = "";
16123 
16124  if(!Utilities->CheckAndReadFileString(SessionFile, OpMode))
16125  {
16126  Utilities->CallLogPop(1767);
16127  return false;
16128  }
16129  else if((OpMode != "PreStart") && (OpMode != "NotPreStart"))
16130  {
16131  Utilities->CallLogPop(1768);
16132  return false;
16133  }
16134  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // RailwayTitle
16135  {
16136  Utilities->CallLogPop(1213);
16137  return false;
16138  }
16139  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile)) // TimetableTitle
16140  {
16141  Utilities->CallLogPop(1214);
16142  return false;
16143  }
16144  if(!Utilities->CheckFileBool(SessionFile))
16145  {
16146  Utilities->CallLogPop(1216);
16147  return false;
16148  }
16149  if(!Utilities->CheckFileBool(SessionFile))
16150  {
16151  Utilities->CallLogPop(1217);
16152  return false;
16153  }
16154  if(!Utilities->CheckFileBool(SessionFile))
16155  {
16156  Utilities->CallLogPop(1218);
16157  return false;
16158  }
16159  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16160  {
16161  Utilities->CallLogPop(1409);
16162  return false;
16163  }
16164  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16165  {
16166  Utilities->CallLogPop(1486);
16167  return false;
16168  }
16169  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16170  {
16171  Utilities->CallLogPop(1487);
16172  return false;
16173  }
16174  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16175  {
16176  Utilities->CallLogPop(1488);
16177  return false;
16178  }
16179  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16180  {
16181  Utilities->CallLogPop(1489);
16182  return false;
16183  }
16184  if(!Utilities->CheckFileInt(SessionFile, -1000000, 1000000))
16185  {
16186  Utilities->CallLogPop(1528);
16187  return false;
16188  }
16189  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16190  {
16191  Utilities->CallLogPop(1725);
16192  return false;
16193  }
16194  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16195  {
16196  Utilities->CallLogPop(1726);
16197  return false;
16198  }
16199  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16200  {
16201  Utilities->CallLogPop(1727);
16202  return false;
16203  }
16204  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16205  {
16206  Utilities->CallLogPop(1728);
16207  return false;
16208  }
16209  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16210  {
16211  Utilities->CallLogPop(1730);
16212  return false;
16213  }
16214  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16215  {
16216  Utilities->CallLogPop(1731);
16217  return false;
16218  }
16219  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16220  {
16221  Utilities->CallLogPop(1732);
16222  return false;
16223  }
16224  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16225  {
16226  Utilities->CallLogPop(1733);
16227  return false;
16228  }
16229  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16230  {
16231  Utilities->CallLogPop(1734);
16232  return false;
16233  }
16234  if(!Utilities->CheckFileStringZeroDelimiter(SessionFile))
16235  {
16236  Utilities->CallLogPop(1789);
16237  return false;
16238  }
16239 
16240  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16241  {
16242  Utilities->CallLogPop(1737);
16243  return false;
16244  }
16245  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16246  {
16247  Utilities->CallLogPop(1738);
16248  return false;
16249  }
16250  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16251  {
16252  Utilities->CallLogPop(1739);
16253  return false;
16254  }
16255  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16256  {
16257  Utilities->CallLogPop(1740);
16258  return false;
16259  }
16260  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16261  {
16262  Utilities->CallLogPop(1741);
16263  return false;
16264  }
16265  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16266  {
16267  Utilities->CallLogPop(1742);
16268  return false;
16269  }
16270  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16271  {
16272  Utilities->CallLogPop(1743);
16273  return false;
16274  }
16275  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16276  {
16277  Utilities->CallLogPop(1744);
16278  return false;
16279  }
16280  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16281  {
16282  Utilities->CallLogPop(1745);
16283  return false;
16284  }
16285  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16286  {
16287  Utilities->CallLogPop(1746);
16288  return false;
16289  }
16290  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16291  {
16292  Utilities->CallLogPop(1747);
16293  return false;
16294  }
16295  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16296  {
16297  Utilities->CallLogPop(1748);
16298  return false;
16299  }
16300  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16301  {
16302  Utilities->CallLogPop(1749);
16303  return false;
16304  }
16305  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16306  {
16307  Utilities->CallLogPop(1750);
16308  return false;
16309  }
16310  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16311  {
16312  Utilities->CallLogPop(1751);
16313  return false;
16314  }
16315  if(!Utilities->CheckFileInt(SessionFile, 0, 1000000))
16316  {
16317  Utilities->CallLogPop(1752);
16318  return false;
16319  }
16320 
16321  if(!Utilities->CheckFileDouble(SessionFile))
16322  {
16323  Utilities->CallLogPop(1753);
16324  return false;
16325  }
16326  if(!Utilities->CheckFileDouble(SessionFile))
16327  {
16328  Utilities->CallLogPop(1754);
16329  return false;
16330  }
16331  if(!Utilities->CheckFileDouble(SessionFile))
16332  {
16333  Utilities->CallLogPop(1755);
16334  return false;
16335  }
16336  if(!Utilities->CheckFileDouble(SessionFile))
16337  {
16338  Utilities->CallLogPop(1756);
16339  return false;
16340  }
16341  if(!Utilities->CheckFileDouble(SessionFile))
16342  {
16343  Utilities->CallLogPop(1757);
16344  return false;
16345  }
16346  Utilities->CallLogPop(1219);
16347  return true;
16348 }
16349 
16350 // ---------------------------------------------------------------------------
16351 
16352 bool TInterface::SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
16353 {
16354  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToSessionFile," + SessionFileStr);
16355  if(!FileExists(TempTTFileName))
16356  {
16357  Utilities->CallLogPop(1862);
16358  return false;
16359  }
16360 
16361  SessionFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
16362  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
16363 
16364  int Handle = FileOpen(TempTTFileName, fmOpenRead);
16365  int Count = 0;
16366 
16367  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
16368  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
16369  // then, but nevertheless have 10 retries before giving message to be on safe side
16370  {
16371  Handle = FileOpen(TempTTFileName, fmOpenRead);
16372  Count++;
16373  Delay(1, 50); // 50mSec delay between tries
16374  if(Count > 10)
16375  {
16376  ShowMessage("Failed to open temporary timetable file. Unable to save the session");
16377  Utilities->CallLogPop(1221);
16378  return false;
16379  }
16380  }
16381 
16382  char *Buffer = new char[10000];
16383  int BytesRead;
16384 
16385  while(true)
16386  {
16387  BytesRead = FileRead(Handle, Buffer, 10000);
16388  SessionFile.write(Buffer, BytesRead);
16389  if(BytesRead < 10000)
16390  break;
16391  }
16392  delete Buffer;
16393  FileClose(Handle);
16394 
16395  SessionFile.close(); // close & re-open in append & text out mode as before so can write text
16396  SessionFile.open(SessionFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
16397 
16398  Utilities->SaveFileString(SessionFile, "***End***"); // marker for end of timetable
16399 // now need to save the TrainOperatingData so can be loaded back into the timetable as is
16400  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.size());
16401  for(unsigned int x = 0; x < TrainController->TrainDataVector.size(); x++)
16402  {
16403  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size());
16404  for(unsigned int y = 0; y < TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size(); y++)
16405  {
16406  Utilities->SaveFileInt(SessionFile, TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID);
16407  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported));
16408  Utilities->SaveFileInt(SessionFile, (short)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry));
16409  }
16410  }
16411  Utilities->CallLogPop(1220);
16412  return true;
16413 }
16414 
16415 // ---------------------------------------------------------------------------
16416 
16417 bool TInterface::SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
16418 {
16419  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTimetableToErrorFile," + ErrorFileStr + "," + TimetableFileName);
16420  if(!FileExists(TimetableFileName))
16421  {
16422  Utilities->CallLogPop(1863);
16423  return false;
16424  }
16425 
16426  ErrorFile.close(); // close & re-open in append & binary mode so LF characters copy as LFs & not CRLFs
16427  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::binary); // file pointer set to end
16428 
16429  int Handle = FileOpen(TimetableFileName, fmOpenRead);
16430  int Count = 0;
16431 
16432  while(Handle < 0) // this type of file use failed when used in SaveTempTimetableFile when used to resave timetable.tmp from
16433  // temp .ttb file, but changed that to avoid so many rapid file actions in quick succession & been OK since
16434  // then, but nevertheless have 10 retries before giving message to be on safe side
16435  {
16436  Handle = FileOpen(TimetableFileName, fmOpenRead);
16437  Count++;
16438  Delay(5, 50); // 50mSec delay between tries
16439  if(Count > 10)
16440  {
16441  Utilities->CallLogPop(1835);
16442  return false;
16443  }
16444  }
16445 
16446  char *Buffer = new char[10000];
16447  int BytesRead;
16448 
16449  while(true)
16450  {
16451  BytesRead = FileRead(Handle, Buffer, 10000);
16452  ErrorFile.write(Buffer, BytesRead);
16453  if(BytesRead < 10000)
16454  break;
16455  }
16456  delete Buffer;
16457  FileClose(Handle);
16458 
16459  ErrorFile.close(); // close & re-open in append & text out mode as before so can write text
16460  ErrorFile.open(ErrorFileStr.c_str(), std::ios_base::app | std::ios_base::out); // file pointer set to end
16461 
16462  Utilities->SaveFileString(ErrorFile, "***End of timetable***"); // marker for end of timetable
16463  Utilities->CallLogPop(1836);
16464  return true;
16465 }
16466 
16467 // ---------------------------------------------------------------------------
16468 
16469 bool TInterface::LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
16470  // the .ttb section is delimited by "***End***"
16471  // create the temporary timetable file in the working folder exactly like the original
16472 {
16473  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTimetableFromSessionFile");
16474  // reset all message flags, stops them being given twice (shouldn't be needed here but add for safety) //new at v2.4.0
16475  TrainController->SSHigh = false;
16476  TrainController->MRSHigh = false;
16477  TrainController->MRSLow = false;
16478  TrainController->MassHigh = false;
16479  TrainController->BFHigh = false;
16480  TrainController->BFLow = false;
16481  TrainController->PwrHigh = false;
16482  TrainController->SigSHigh = false;
16483  TrainController->SigSLow = false;
16484  if((TempTTFileName != "") && FileExists(TempTTFileName))
16485  {
16486  DeleteFile(TempTTFileName);
16487  }
16488  int TempTTFileNumber = 0;
16489 
16490  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
16491  {
16492  TempTTFileNumber++;
16493  }
16494  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
16495 
16496  std::ofstream TTBFile(TempTTFileName.c_str()); // use text mode as SessionFile is in text mode, so CRLFs read as LFs, and LFs write as CRLFs.
16497  int Count;
16498  char Zero = '\0';
16499 
16500  if(!TTBFile.fail())
16501  {
16502  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
16503  char TempChar = (char)(SessionFile.peek()); // have a look at the next character, if it's '\n'
16504  if(TempChar == '\n')
16505  SessionFile.get(TempChar); // then get rid of it, else leave it in as part of the first line
16506  if(!SessionFile.getline(Buffer, 10000, '\0'))
16507  {
16508  TTBFile.close();
16509  DeleteFile(TempTTFileName);
16510  delete Buffer;
16511  Utilities->CallLogPop(1222);
16512  return false;
16513  }
16514  Count = 0;
16515  for(int x = 0; x < 10000; x++)
16516  {
16517  if(Buffer[x] != '\0')
16518  Count++;
16519  else
16520  break;
16521  }
16522  while(AnsiString(Buffer) != "***End***")
16523  {
16524  TTBFile.write(Buffer, Count);
16525  TTBFile.write(&Zero, 1);
16526 // TTBFile.write(&NewLine, 1);
16527  if(!SessionFile.getline(Buffer, 10000, '\0'))
16528  {
16529  TTBFile.close();
16530  DeleteFile(TempTTFileName);
16531  delete Buffer;
16532  Utilities->CallLogPop(1223);
16533  return false;
16534  }
16535  Count = 0;
16536  for(int x = 0; x < 10000; x++)
16537  {
16538  if(Buffer[x] != '\0')
16539  Count++;
16540  else
16541  break;
16542  }
16543  }
16544  TTBFile.close();
16545  delete Buffer;
16546 // SaveTempTimetableFile(1, TTBFileName); no need, already has required name
16547 // now create the internal timetable from the .tmp file
16548  bool GiveMessagesFalse = false;
16549  bool CheckLocationsExistInRailwayTrue = true;
16550  if(TrainController->TimetableIntegrityCheck(1, TempTTFileName.c_str(), GiveMessagesFalse, CheckLocationsExistInRailwayTrue))
16551  {
16552  std::ifstream TTBLFile(TempTTFileName.c_str(), std::ios_base::binary);
16553  if(TTBLFile.is_open())
16554  {
16555  bool SessionFileTrue = true;
16556  if(!(BuildTrainDataVectorForLoadFile(1, TTBLFile, GiveMessagesFalse, CheckLocationsExistInRailwayTrue, SessionFileTrue)))
16557  {
16558  TTBLFile.close();
16559  DeleteFile(TempTTFileName);
16560  Utilities->CallLogPop(1224);
16561  return false;
16562  }
16563  }
16564  else
16565  {
16566  DeleteFile(TempTTFileName);
16567  Utilities->CallLogPop(1225);
16568  return false;
16569  }
16570  } // if(FileIntegrityCheck(TTBFileName.c_str()))
16571  else
16572  {
16573  DeleteFile(TempTTFileName);
16574  Utilities->CallLogPop(1226);
16575  return false;
16576  }
16577 // DeleteFile(TempTTFileName); no, need to save it for later session saves
16578 
16579  // now need to load the TrainOperatingData so can be loaded back into the timetable
16580  int NumberOfTrainEntries = Utilities->LoadFileInt(SessionFile);
16581  if(NumberOfTrainEntries != (int)(TrainController->TrainDataVector.size()))
16582  {
16583  Utilities->CallLogPop(1811);
16584  return false;
16585  }
16586  for(int x = 0; x < NumberOfTrainEntries; x++)
16587  {
16588  int NumberOfTrains = Utilities->LoadFileInt(SessionFile);
16589  if(NumberOfTrains != (int)(TrainController->TrainDataVector.at(x).TrainOperatingDataVector.size()))
16590  {
16591  Utilities->CallLogPop(1812);
16592  return false;
16593  }
16594  for(int y = 0; y < NumberOfTrains; y++)
16595  {
16596  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).TrainID = Utilities->LoadFileInt(SessionFile);
16597  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).EventReported = (TActionEventType)(Utilities->LoadFileInt(SessionFile));
16598  TrainController->TrainDataVector.at(x).TrainOperatingDataVector.at(y).RunningEntry = (TRunningEntry)(Utilities->LoadFileInt(SessionFile));
16599  }
16600  }
16601  Utilities->CallLogPop(1227);
16602  return true;
16603  }
16604  else
16605  {
16606  Utilities->CallLogPop(1228);
16607  return false;
16608  }
16609 }
16610 
16611 // ---------------------------------------------------------------------------
16612 
16613 bool TInterface::CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
16614  // the .ttb section is delimited by '\0' followed by "***End***" & has been saved in binary mode, i.e. no '\0'
16615  // string delimiters between entries, this check function just checks the (non-zero terminated) string entries in the file without
16616  // trying to build a timetable - that's done during load
16617 {
16618  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTimetableFromSessionFile");
16619  AnsiString OutString;
16620 
16621  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
16622  {
16623  Utilities->CallLogPop(1229);
16624  return false;
16625  }
16626  while(OutString != "***End***")
16627  {
16628  if(!Utilities->CheckAndReadFileString(SessionFile, OutString))
16629  {
16630  Utilities->CallLogPop(1230);
16631  return false;
16632  }
16633  }
16634 // now need to check the TrainOperatingData, which was saved in text mode
16635  if(SessionFile.fail())
16636  {
16637  Utilities->CallLogPop(1231);
16638  return false;
16639  }
16640  int NumberOfTrainEntries;
16641 
16642  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrainEntries))
16643  {
16644  Utilities->CallLogPop(1232);
16645  return false;
16646  }
16647  for(int x = 0; x < NumberOfTrainEntries; x++)
16648  {
16649  int NumberOfTrains;
16650  if(!Utilities->CheckAndReadFileInt(SessionFile, 0, 10000, NumberOfTrains))
16651  {
16652  Utilities->CallLogPop(1233);
16653  return false;
16654  }
16655  for(int y = 0; y < NumberOfTrains; y++)
16656  {
16657  if(!Utilities->CheckFileInt(SessionFile, -1, 1000000)) // TrainID
16658  {
16659  Utilities->CallLogPop(1234);
16660  return false;
16661  }
16662  if(!Utilities->CheckFileInt(SessionFile, 0, 30)) // EventReported
16663  {
16664  Utilities->CallLogPop(1235);
16665  return false;
16666  }
16667  if(!Utilities->CheckFileInt(SessionFile, 0, 2)) // RunningEntry
16668  {
16669  Utilities->CallLogPop(1236);
16670  return false;
16671  }
16672  }
16673  }
16674  Utilities->CallLogPop(1237);
16675  return true;
16676 }
16677 
16678 // ---------------------------------------------------------------------------
16679 
16680 bool TInterface::BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
16681 {
16682  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForLoadFile," + AnsiString((short)GiveMessages));
16683  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
16684  bool EndOfFile = false;
16685  int Count = 0;
16686  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
16687 
16688  while(!EndOfFile)
16689  {
16690  TTBLFile.getline(TrainTimetableString, 10000, '\0');
16691  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
16692  { // may still have eof even if read a line (no CRLF at end), and
16693  // if so need to process it
16694  EndOfFile = true;
16695  break;
16696  }
16697  AnsiString OneLine(TrainTimetableString);
16698  bool FinalCallTrue = true;
16699  while((Count == 0) && !TrainController->ProcessOneTimetableLine(3, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
16700  CheckLocationsExistInRailway)) // get rid of lines before the start time
16701  {
16702  TTBLFile.getline(TrainTimetableString, 10000, '\0');
16703  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
16704  {
16705  TTBLFile.close();
16706  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
16707  }
16708  OneLine = AnsiString(TrainTimetableString);
16709  }
16710  // here when have accepted the start time
16711  if(Count == 0)
16712  {
16713  Count++; // increment past the start time
16714  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
16715  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
16716  {
16717  EndOfFile = true;
16718  OneLine = "";
16719  }
16720  else
16721  OneLine = AnsiString(TrainTimetableString);
16722  }
16723  if(!TrainController->ProcessOneTimetableLine(4, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
16724  {
16725  TTBLFile.close();
16726  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
16727  }
16728  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
16729  {
16730  TTBLFile.close();
16731  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
16732  }
16733  Count++;
16734  }
16735  TTBLFile.close();
16736  delete TrainTimetableString;
16737 // here when first pass actions completed successfully
16738  if(!TrainController->SecondPassActions(0, GiveMessages)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
16739  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
16740  // messages given in function if errors & vector cleared
16741  {
16742  if(GiveMessages)
16743  ShowMessage("Timetable secondary integrity check failed - unable to load");
16744  Utilities->CallLogPop(1238);
16745  return false;
16746  }
16747  else
16748  {
16749 // TimetableLoaded = true;
16750  if(!SessionFile) // new timetable being loaded so need new TimetableTitle, if SessionFile true then already have it from LoadInterface
16751  {
16752  for(int x = TimetableDialog->FileName.Length(); x > 0; x--)
16753  {
16754  if(TimetableDialog->FileName[x] == '\\')
16755  {
16756  TimetableTitle = TimetableDialog->FileName.SubString(x + 1, TimetableDialog->FileName.Length() - x - 4);
16757  SetCaption(4);
16758  break;
16759  }
16760  }
16761  }
16762 // if(GiveMessages) //only set BaseMode if have manually loaded a timetable changed for the below in v2.4.0
16763  if(!SessionFile) // only set BaseMode if have manually loaded a timetable, i.e SessionFile is false
16764  {
16765  Level1Mode = BaseMode;
16766  SetLevel1Mode(28);
16767  }
16768  }
16769  Utilities->CallLogPop(1239);
16770  return true;
16771 }
16772 
16773 // ---------------------------------------------------------------------------
16774 
16775 bool TInterface::BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
16776 {
16777  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildTrainDataVectorForValidateFile," + AnsiString((short)GiveMessages));
16778  TrainController->TrainDataVector.clear(); // get rid of any earlier timetable
16779  bool EndOfFile = false;
16780  int Count = 0;
16781  char *TrainTimetableString = new char[10000]; // enough for ~ 200 stations at 50 chars/station, should be adequate!
16782 
16783  while(!EndOfFile)
16784  {
16785  TTBLFile.getline(TrainTimetableString, 10000, '\0');
16786  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // stores a null in 1st position if doesn't load any characters
16787  { // may still have eof even if read a line (no CRLF at end), and
16788  // if so need to process it
16789  EndOfFile = true;
16790  break;
16791  }
16792  AnsiString OneLine(TrainTimetableString);
16793  bool FinalCallTrue = true;
16794  while((Count == 0) && !TrainController->ProcessOneTimetableLine(0, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages,
16795  CheckLocationsExistInRailway)) // get rid of lines before the start time
16796  {
16797  TTBLFile.getline(TrainTimetableString, 10000, '\0');
16798  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
16799  {
16800  TTBLFile.close();
16801  throw Exception("Timetable FinalCall error - no start time on own line, Count = 0");
16802  }
16803  OneLine = AnsiString(TrainTimetableString);
16804  }
16805  // here when have accepted the start time
16806  if(Count == 0)
16807  {
16808  Count++; // increment past the start time
16809  TTBLFile.getline(TrainTimetableString, 10000, '\0'); // get next line after start time
16810  if(TTBLFile.eof() && (TrainTimetableString[0] == '\0')) // see above
16811  {
16812  EndOfFile = true;
16813  OneLine = "";
16814  }
16815  else
16816  OneLine = AnsiString(TrainTimetableString);
16817  }
16818  if(!TrainController->ProcessOneTimetableLine(1, Count, OneLine, EndOfFile, FinalCallTrue, GiveMessages, CheckLocationsExistInRailway))
16819  {
16820  TTBLFile.close();
16821  throw Exception("Timetable FinalCall error in processing one timetable line, Count = " + AnsiString(Count));
16822  }
16823  if(EndOfFile && (Count < 2)) // Timetable must contain at least two relevant lines, one for start time and at least one train
16824  {
16825  TTBLFile.close();
16826  throw Exception("Timetable FinalCall error - too few or no relevant entries, Count = " + AnsiString(Count));
16827  }
16828  Count++;
16829  }
16830  TTBLFile.close();
16831  delete TrainTimetableString;
16832 // here when first pass actions completed successfully
16833  if(!TrainController->SecondPassActions(1, GiveMessages)) // Check for matching join/split HeadCodes, check increasing times & matching split/join
16834  // times, complete arrival & departure times for each TT line, check & complete train info for each type of start,
16835  // messages given in function if errors & vector cleared
16836  {
16837 // if(GiveMessages) ShowMessage("Timetable secondary integrity check failed");
16838 // above dropped in v2.4.0 as all called functions give own messages
16839  Utilities->CallLogPop(1665);
16840  return false;
16841  }
16842  Utilities->CallLogPop(1666);
16843  return true;
16844 }
16845 
16846 // ---------------------------------------------------------------------------
16847 
16848 bool TInterface::SessionFileIntegrityCheck(int Caller, AnsiString FileName)
16849 /* Here need to check as far as timetable, then go back and load the track, because the timetable compilation check
16850  relies on the track vector and map being in place. Won't affect the later load because the vector and map are cleared
16851  before loading.
16852 
16853  Although this appears cumbersome, I initially used tellg() & seekg() to reposition the file pointer without having to do
16854  all this backtracking. However after many problems I eventually found that tellg() sometimes returns false values,
16855  which cause problems when reloaded using seekg(). This must be a compiler problem, though I could find no mention of it
16856  in the CBuilder4 issues list or on the web. The full write-up is at the end of this unit.
16857 
16858  Also, with hindsight, I wish I had just saved and reloaded the timetable vectors rather than the text of the timetable. That
16859  would probably have been easier. To change it now though would cause compatibility problems with sessions created by earlier versions.
16860 */
16861 {
16862  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SessionFileIntegrityCheck," + FileName);
16863  std::ifstream InFile(FileName.c_str());
16864 // first pass as far as timetable
16865  int NumberOfActiveElements;
16866  bool GraphicsFollow = false;
16867 
16868  if(InFile.is_open())
16869  {
16871  // expected to be "***Interface***" for original version or "Version + : ***Interface***" for later releases + ExcessLCDownMins added as float after v2.2.0
16872  {
16873  InFile.close();
16874  Utilities->CallLogPop(1240);
16875  return false;
16876  }
16877  if(!CheckInterface(0, InFile))
16878  {
16879  InFile.close();
16880  Utilities->CallLogPop(1241);
16881  return false;
16882  }
16883  // check track elements
16884  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
16885  {
16886  InFile.close();
16887  Utilities->CallLogPop(1242);
16888  return false;
16889  }
16890  if(!Track->CheckTrackElementsInFile(2, NumberOfActiveElements, GraphicsFollow, InFile))
16891  {
16892  InFile.close();
16893  Utilities->CallLogPop(1243);
16894  return false;
16895  }
16896  if(InFile.fail())
16897  {
16898  InFile.close();
16899  Utilities->CallLogPop(1244);
16900  return false;
16901  }
16902  // check text elements
16903  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
16904  {
16905  InFile.close();
16906  Utilities->CallLogPop(1245);
16907  return false;
16908  }
16909  if(!TextHandler->CheckTextElementsInFile(1, InFile))
16910  {
16911  InFile.close();
16912  Utilities->CallLogPop(1246);
16913  return false;
16914  }
16915  if(InFile.fail())
16916  {
16917  InFile.close();
16918  Utilities->CallLogPop(1247);
16919  return false;
16920  }
16921  // check PrefDir elements
16922  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
16923  {
16924  InFile.close();
16925  Utilities->CallLogPop(1248);
16926  return false;
16927  }
16928  if(!EveryPrefDir->CheckOnePrefDir(1, NumberOfActiveElements, InFile))
16929  {
16930  InFile.close();
16931  Utilities->CallLogPop(1249);
16932  return false;
16933  }
16934  if(InFile.fail())
16935  {
16936  InFile.close();
16937  Utilities->CallLogPop(1250);
16938  return false;
16939  }
16940  // check graphics
16941  if(GraphicsFollow)
16942  {
16943  if(!Track->CheckUserGraphics(1, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
16944  {
16945  InFile.close();
16946  Utilities->CallLogPop(2187);
16947  return false;
16948  }
16949  if(InFile.fail())
16950  {
16951  InFile.close();
16952  Utilities->CallLogPop(2188);
16953  return false;
16954  }
16955  }
16956  // check routes
16957  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
16958  {
16959  InFile.close();
16960  Utilities->CallLogPop(1251);
16961  return false;
16962  }
16963  if(!AllRoutes->CheckRoutes(0, NumberOfActiveElements, InFile))
16964  {
16965  InFile.close();
16966  Utilities->CallLogPop(1252);
16967  return false;
16968  }
16969  if(InFile.fail())
16970  {
16971  InFile.close();
16972  Utilities->CallLogPop(1253);
16973  return false;
16974  }
16975  // check LockedRoutes
16976  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
16977  {
16978  InFile.close();
16979  Utilities->CallLogPop(1254);
16980  return false;
16981  }
16982  if(!TrainController->CheckSessionLockedRoutes(0, InFile))
16983  {
16984  InFile.close();
16985  Utilities->CallLogPop(1255);
16986  return false;
16987  }
16988  if(InFile.fail())
16989  {
16990  InFile.close();
16991  Utilities->CallLogPop(1256);
16992  return false;
16993  }
16994  // check ContinuationAutoSigs
16995  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
16996  {
16997  InFile.close();
16998  Utilities->CallLogPop(1257);
16999  return false;
17000  }
17002  {
17003  InFile.close();
17004  Utilities->CallLogPop(1258);
17005  return false;
17006  }
17007  if(InFile.fail())
17008  {
17009  InFile.close();
17010  Utilities->CallLogPop(1259);
17011  return false;
17012  }
17013  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
17014  AnsiString TempString = Utilities->LoadFileString(InFile);
17015  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
17016  {
17017  InFile.close();
17018  Utilities->CallLogPop(1964);
17019  return false;
17020  }
17021  if(TempString == "***BarriersDownVector***")
17022  {
17023  if(!Track->CheckActiveLCVector(0, InFile))
17024  {
17025  InFile.close();
17026  Utilities->CallLogPop(1965);
17027  return false;
17028  }
17029  if(InFile.fail())
17030  {
17031  InFile.close();
17032  Utilities->CallLogPop(1966);
17033  return false;
17034  }
17035  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
17036  {
17037  InFile.close();
17038  Utilities->CallLogPop(1260);
17039  return false;
17040  }
17041  }
17042  // check timetable (marker string already checked immediately above)
17043  if(!CheckTimetableFromSessionFile(0, InFile))
17044  {
17045  InFile.close();
17046  Utilities->CallLogPop(1261);
17047  return false;
17048  }
17049  if(InFile.fail())
17050  {
17051  InFile.close();
17052  Utilities->CallLogPop(1262);
17053  return false;
17054  }
17055  }
17056  else
17057  {
17058  InFile.close();
17059  ShowMessage("Session file failed to open, unable to load session. Ensure that there is a folder named " + SESSION_DIR_NAME +
17060  " in the folder where the 'Railway.exe' program file resides");
17061  Utilities->CallLogPop(1263);
17062  return false;
17063  }
17064 
17065 // now ready for the 2nd pass for timetable loading and checking
17066  InFile.close();
17067  InFile.open(FileName.c_str());
17068  if(InFile.is_open())
17069  {
17071  {
17072  InFile.close();
17073  Utilities->CallLogPop(1264);
17074  return false;
17075  }
17076  if(!CheckInterface(1, InFile))
17077  {
17078  InFile.close();
17079  Utilities->CallLogPop(1265);
17080  return false;
17081  }
17082  // load track elements
17083  if(!Utilities->CheckAndCompareFileString(InFile, "***Track***"))
17084  {
17085  InFile.close();
17086  Utilities->CallLogPop(1266);
17087  return false;
17088  }
17089  bool GraphicsFollow = false;
17090  Track->LoadTrack(2, InFile, GraphicsFollow); // load the track this time
17091  if(InFile.fail())
17092  {
17093  InFile.close();
17094  Utilities->CallLogPop(1267);
17095  return false;
17096  }
17097  // check text elements
17098  if(!Utilities->CheckAndCompareFileString(InFile, "***Text***"))
17099  {
17100  InFile.close();
17101  Utilities->CallLogPop(1268);
17102  return false;
17103  }
17104  if(!TextHandler->CheckTextElementsInFile(2, InFile))
17105  {
17106  InFile.close();
17107  Utilities->CallLogPop(1269);
17108  return false;
17109  }
17110  if(InFile.fail())
17111  {
17112  InFile.close();
17113  Utilities->CallLogPop(1270);
17114  return false;
17115  }
17116  // check PrefDir elements
17117  if(!Utilities->CheckAndCompareFileString(InFile, "***PrefDirs***"))
17118  {
17119  InFile.close();
17120  Utilities->CallLogPop(1271);
17121  return false;
17122  }
17123  if(!EveryPrefDir->CheckOnePrefDir(2, NumberOfActiveElements, InFile))
17124  {
17125  InFile.close();
17126  Utilities->CallLogPop(1272);
17127  return false;
17128  }
17129  if(InFile.fail())
17130  {
17131  InFile.close();
17132  Utilities->CallLogPop(1273);
17133  return false;
17134  }
17135  // check graphics
17136  if(GraphicsFollow)
17137  {
17138  if(!Track->CheckUserGraphics(2, InFile, CurDir + "\\" + USERGRAPHICS_DIR_NAME)) // include path to Graphics folder
17139  {
17140  InFile.close();
17141  Utilities->CallLogPop(2189);
17142  return false;
17143  }
17144  if(InFile.fail())
17145  {
17146  InFile.close();
17147  Utilities->CallLogPop(2190);
17148  return false;
17149  }
17150  }
17151  // check routes
17152  if(!Utilities->CheckAndCompareFileString(InFile, "***Routes***"))
17153  {
17154  InFile.close();
17155  Utilities->CallLogPop(1274);
17156  return false;
17157  }
17158  if(!AllRoutes->CheckRoutes(1, NumberOfActiveElements, InFile))
17159  {
17160  InFile.close();
17161  Utilities->CallLogPop(1275);
17162  return false;
17163  }
17164  if(InFile.fail())
17165  {
17166  InFile.close();
17167  Utilities->CallLogPop(1276);
17168  return false;
17169  }
17170  // check LockedRoutes
17171  if(!Utilities->CheckAndCompareFileString(InFile, "***Locked routes***"))
17172  {
17173  InFile.close();
17174  Utilities->CallLogPop(1277);
17175  return false;
17176  }
17177  if(!TrainController->CheckSessionLockedRoutes(1, InFile))
17178  {
17179  InFile.close();
17180  Utilities->CallLogPop(1278);
17181  return false;
17182  }
17183  if(InFile.fail())
17184  {
17185  InFile.close();
17186  Utilities->CallLogPop(1279);
17187  return false;
17188  }
17189  // check ContinuationAutoSigs
17190  if(!Utilities->CheckAndCompareFileString(InFile, "***ContinuationAutoSigEntries***"))
17191  {
17192  InFile.close();
17193  Utilities->CallLogPop(1280);
17194  return false;
17195  }
17197  {
17198  InFile.close();
17199  Utilities->CallLogPop(1281);
17200  return false;
17201  }
17202  if(InFile.fail())
17203  {
17204  InFile.close();
17205  Utilities->CallLogPop(1282);
17206  return false;
17207  }
17208  // check BarriersDownVector, but ensure backwards compatibility with earlier files which don't have this section
17209  AnsiString TempString = Utilities->LoadFileString(InFile);
17210  if((TempString != "***BarriersDownVector***") && (TempString != "***Timetable***"))
17211  {
17212  InFile.close();
17213  Utilities->CallLogPop(1967);
17214  return false;
17215  }
17216  if(TempString == "***BarriersDownVector***")
17217  {
17218  if(!Track->CheckActiveLCVector(0, InFile))
17219  {
17220  InFile.close();
17221  Utilities->CallLogPop(1968);
17222  return false;
17223  }
17224  if(InFile.fail())
17225  {
17226  InFile.close();
17227  Utilities->CallLogPop(1969);
17228  return false;
17229  }
17230  if(!Utilities->CheckAndCompareFileString(InFile, "***Timetable***"))
17231  {
17232  InFile.close();
17233  Utilities->CallLogPop(1283);
17234  return false;
17235  }
17236  }
17237  // check timetable (marker string already checked)
17238  if(!LoadTimetableFromSessionFile(1, InFile))
17239  {
17240  InFile.close();
17241  Utilities->CallLogPop(1284);
17242  return false;
17243  }
17244  if(InFile.fail())
17245  {
17246  InFile.close();
17247  Utilities->CallLogPop(1285);
17248  return false;
17249  }
17250  // check timetable clock
17251  if(!Utilities->CheckAndCompareFileString(InFile, "***TimetableClock***"))
17252  {
17253  InFile.close();
17254  Utilities->CallLogPop(1286);
17255  return false;
17256  }
17257  if(!Utilities->CheckFileDouble(InFile))
17258  {
17259  InFile.close();
17260  Utilities->CallLogPop(1287);
17261  return false;
17262  }
17263  // check trains
17264  if(!Utilities->CheckAndCompareFileString(InFile, "***Trains***"))
17265  {
17266  InFile.close();
17267  Utilities->CallLogPop(1288);
17268  return false;
17269  }
17270  if(!TrainController->CheckSessionTrains(0, InFile))
17271  {
17272  InFile.close();
17273  Utilities->CallLogPop(1289);
17274  return false;
17275  }
17276  if(InFile.fail())
17277  {
17278  InFile.close();
17279  Utilities->CallLogPop(1290);
17280  return false;
17281  }
17282  if(!Utilities->CheckAndCompareFileString(InFile, "***Performance file***"))
17283  {
17284  InFile.close();
17285  Utilities->CallLogPop(1291);
17286  return false;
17287  }
17288  if(!CheckPerformanceFile(0, InFile))
17289  {
17290  InFile.close();
17291  Utilities->CallLogPop(1292);
17292  return false;
17293  }
17294  char TempChar;
17295  InFile.get(TempChar);
17296  while(!InFile.eof() && ((TempChar == '\n') || (TempChar == '\0'))) // when emerge from here either have eof or '*'
17297  {
17298  InFile.get(TempChar);
17299  }
17300  if(!InFile.eof()) // additional checks needed
17301  {
17302  if(!Utilities->CheckFileString(InFile))
17303  {
17304  InFile.close();
17305  Utilities->CallLogPop(2198);
17306  return false;
17307  }
17308  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // TrainController->AvHoursIntValue
17309  {
17310  InFile.close();
17311  Utilities->CallLogPop(2199);
17312  return false;
17313  }
17314  if(!Utilities->CheckFileInt(InFile, 0, 1000000)) // number of train failures
17315  {
17316  InFile.close();
17317  Utilities->CallLogPop(2200);
17318  return false;
17319  }
17320  // now check any failed trains along with their OriginalPowerAtRail values
17321  Utilities->CheckFileString(InFile); // discard "***Failed Trains***"
17322  int IDVal;
17323  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal)) // train ID or -1 for no more failed trains,
17324  {
17325  InFile.close();
17326  Utilities->CallLogPop(2201);
17327  return false;
17328  }
17329  double PowerDouble;
17330  while(IDVal != -1)
17331  {
17332  Utilities->CheckFileDouble(InFile); // original power
17333  if(!Utilities->CheckAndReadFileInt(InFile, -1, 1000000, IDVal))
17334  {
17335  InFile.close();
17336  Utilities->CallLogPop(2202);
17337  return false;
17338  }
17339  }
17340  }
17341  InFile.close();
17342  }
17343  else
17344  {
17345  InFile.close();
17346  Utilities->CallLogPop(1293);
17347  return false;
17348  }
17349  Utilities->CallLogPop(1294);
17350  return true;
17351 }
17352 
17353 // ---------------------------------------------------------------------------
17354 
17355 void TInterface::LoadPerformanceFile(int Caller, std::ifstream &InFile)
17356  // Note that the file integrity has already been checked using CheckPerformanceFile
17357 {
17358  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPerformanceFile");
17359  AnsiString TempString = "", Line1 = "", Line2 = "", Line3 = "", Line4 = "", Line5 = "";
17360  char *Buffer = new char[1000];
17361  char TempChar;
17362 
17363  InFile.get(TempChar); // '\n'
17364  InFile.getline(Buffer, 1000);
17365  TempString = AnsiString(Buffer);
17366  while(TempString != "***End of performance file***")
17367  {
17368  PerformanceLogBox->Lines->Add(TempString);
17369  Utilities->PerformanceFile << TempString.c_str() << '\n';
17370  InFile.getline(Buffer, 1000);
17371  TempString = AnsiString(Buffer);
17372  }
17373  delete Buffer;
17374  Utilities->CallLogPop(1295);
17375 }
17376 
17377 // ---------------------------------------------------------------------------
17378 
17379 bool TInterface::CheckPerformanceFile(int Caller, std::ifstream &InFile)
17380 {
17381  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPerformanceFile");
17382  AnsiString TempString = "";
17383  char TempChar;
17384 
17385  InFile.get(TempChar);
17386  if(TempChar != '\n')
17387  {
17388  Utilities->CallLogPop(1296);
17389  return false;
17390  }
17391  if(!Utilities->CheckAndReadFileString(InFile, TempString))
17392  {
17393  Utilities->CallLogPop(1297);
17394  return false;
17395  }
17396  while(TempString != "***End of performance file***")
17397  {
17398  if(!Utilities->CheckAndReadFileString(InFile, TempString))
17399  {
17400  Utilities->CallLogPop(1298);
17401  return false;
17402  }
17403  }
17404  Utilities->CallLogPop(1299);
17405  return true;
17406 }
17407 
17408 // ---------------------------------------------------------------------------
17409 
17410 void TInterface::SavePerformanceFile(int Caller, std::ofstream &OutFile)
17411 {
17412  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePerformanceFile");
17413  AnsiString Text = PerformanceLogBox->Text;
17414 
17415  while(Text != "")
17416  {
17417  AnsiString OneLine = Text.SubString(1, Text.Pos('\x0D'));
17418  while((OneLine.Length() > 0) && OneLine[OneLine.Length()] < ' ')
17419  OneLine.SetLength(OneLine.Length() - 1); // get rid of trailing control characters
17420  Text = Text.SubString(Text.Pos('\x0D'), Text.Length());
17421  while((Text.Length() > 0) && Text[1] < ' ')
17422  Text = Text.SubString(2, (Text.Length() - 1)); // get rid of leading control characters
17423  OutFile << OneLine.c_str() << '\n';
17424  }
17425  Utilities->CallLogPop(1300);
17426 }
17427 
17428 // ---------------------------------------------------------------------------
17429 
17431 {
17432  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteButtonsInfoCaptionAndRouteNotStarted");
17433  if(EveryPrefDir->PrefDirSize() > 0)
17434  {
17435  if(AutoSigsFlag)
17436  {
17437  AutoSigsButton->Enabled = false;
17438  SigPrefButton->Enabled = true;
17439  UnrestrictedButton->Enabled = true;
17440  InfoPanel->Visible = true;
17441  if(Level2OperMode == PreStart)
17442  InfoPanel->Caption = "PRE-START: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
17443  else
17444  InfoPanel->Caption = "OPERATING: Select AUTOMATIC SIGNAL ROUTE start signal, or left click points to change manually";
17445  InfoCaptionStore = InfoPanel->Caption;
17446  }
17447  else if(ConsecSignalsRoute) // PreferredRoute always same as ConsecSignalsRoute
17448  {
17449  AutoSigsButton->Enabled = true;
17450  SigPrefButton->Enabled = false;
17451  UnrestrictedButton->Enabled = true;
17452  InfoPanel->Visible = true;
17453  if(Level2OperMode == PreStart)
17454  InfoPanel->Caption = "PRE-START: Select PREFERRED ROUTE start signal, or left click points to change manually";
17455  else
17456  InfoPanel->Caption = "OPERATING: Select PREFERRED ROUTE start signal, or left click points to change manually";
17457  InfoCaptionStore = InfoPanel->Caption;
17458  }
17459  else
17460  {
17461  AutoSigsButton->Enabled = true;
17462  SigPrefButton->Enabled = true;
17463  UnrestrictedButton->Enabled = false;
17464  InfoPanel->Visible = true;
17465  if(Level2OperMode == PreStart)
17466  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17467  else
17468  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17469  InfoCaptionStore = InfoPanel->Caption;
17470  }
17471  }
17472  else
17473  {
17474  AutoSigsButton->Enabled = false;
17475  SigPrefButton->Enabled = false;
17476  UnrestrictedButton->Enabled = false;
17477  InfoPanel->Visible = true;
17478  if(Level2OperMode == PreStart)
17479  InfoPanel->Caption = "PRE-START: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17480  else
17481  InfoPanel->Caption = "OPERATING: Select UNRESTRICTED ROUTE start location, or left click points to change manually";
17482  InfoCaptionStore = InfoPanel->Caption;
17483  }
17485  {
17486  RouteCancelButton->Enabled = true;
17487  }
17488  else
17489  {
17490  RouteCancelButton->Enabled = false;
17491  }
17493  AutoRouteStartMarker->PlotOriginal(37, Display); // so start marker will replot if had selected start before pause & zoom
17496  Utilities->CallLogPop(1301);
17497 }
17498 
17499 // ---------------------------------------------------------------------------
17500 
17502 {
17503  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetPausedOrZoomedInfoCaption");
17504  if(Display->ZoomOutFlag)
17505  {
17506  InfoPanel->Visible = true;
17507  InfoPanel->Caption = "Left click screen to zoom in at that position";
17508  }
17509  else if(Level2OperMode == Paused)
17510  {
17511  InfoPanel->Visible = true;
17512  InfoPanel->Caption = "PAUSED: Railway state changes disabled";
17513  }
17514 // otherwise do nothing
17515  Utilities->CallLogPop(1302);
17516 }
17517 
17518 // ---------------------------------------------------------------------------
17519 
17521 {
17522  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DisableRouteButtons");
17523  RouteCancelButton->Enabled = false;
17524  AutoSigsButton->Enabled = false;
17525  SigPrefButton->Enabled = false;
17526  UnrestrictedButton->Enabled = false;
17527  Utilities->CallLogPop(1303);
17528 }
17529 
17530 // ---------------------------------------------------------------------------
17531 
17533  // no need for call logging as already failed
17534 {
17535 /*
17536  In order to reload as a session file:
17537 
17538  NB: Don't change it to a .txt file, as the '\0' characters [shown as a small square in wordpad] will be changed to spaces if it is subsequently saved
17539  strip out:-
17540 
17541  [since adding user graphics after prefdirs need to take this into account]
17542 
17543  up to but excluding ***Interface***
17544  from & including ***ConstructPrefDir PrefDirVector***
17545  to but excluding ***PrefDirs***
17546  if there is a single line ***UserGraphics*** delete it (won't be present if no graphics)
17547  from & including ***ConstructRoute PrefDirVector***
17548  to but excluding ***Routes***
17549  from & including ***ChangingLCVector*** to but excluding ***Timetable*** [if have ***No timetable loaded*** then can't use as a session file]
17550  from & including ***No editing timetable*** or ***Editing timetable - [title]***
17551  to but excluding ***TimetableClock***
17552  and save as a .ssn file.
17553 
17554  In order to load as a railway file:
17555 
17556  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
17557 
17558  note or copy the version information at the top of the file
17559  copy the two numbers on rows 7 & 8 below ***Interface*** (i.e ***Interface*** = row 0) on their own lines immediately after the ***Track*** line (these become DisplayOffsetH & V)
17560  strip out up to but excluding ***Track*** - this is needed to keep the \0 entry at end of ***Track*** [shown as a small square in wordpad]
17561  add the version number either before or instead of ***Track***, ensuring that the \0 is retained
17562  the next line after the two insertions should contain the number of active elements.
17563  strip out ***Text*** including the \0
17564  strip out from & including ***ConstructPrefDir PrefDirVector*** to & including ***PrefDirs*** (and the \0's)
17565  strip out ***UserGraphics*** including the \0
17566  strip out from & including ***ConstructRoute PrefDirVector*** to the end of the file
17567  rename as .dev or .rly file
17568 
17569  BUT - note that signals (and points, though they won't show) will be set as they were left. To reset to red, load a suitable timetable & select
17570  'Operate' then 'Exit operation'.
17571 */
17572 
17573 /*
17574  In order to extract a timetable:
17575 
17576  NB: Don't change it to a .txt file, as the '\0' characters will be changed to spaces if it is subsequently saved
17577 
17578  set wordwrap to window on
17579  strip out all to and including ***Timetable*** or ***Editing timetable.... depending which is to be saved
17580  ensure any text before start time ends with /0, otherwise don't need the \0
17581  strip out all after the final /0 immediately before ***End*** or ***End of timetable***, but ensure leave the final /0
17582  save as a .ttb file
17583 */
17584 
17585  Screen->Cursor = TCursor(-11); // Hourglass;
17586  AnsiString ErrorFileStr = CurDir + "\\errorlog.err";
17587  std::ofstream ErrorFile(ErrorFileStr.c_str());
17588 
17589  if(!(ErrorFile.fail()))
17590  {
17591 // save mouse position relative to mainscreen
17592  int ScreenX = Mouse->CursorPos.x - MainScreen->ClientOrigin.x;
17593  int ScreenY = Mouse->CursorPos.y - MainScreen->ClientOrigin.y;
17594  AnsiString MouseStr = "Posx: " + AnsiString(ScreenX) + "; Posy: " + AnsiString(ScreenY);
17595  Utilities->SaveFileString(ErrorFile, MouseStr);
17596  Utilities->SaveFileInt(ErrorFile, MissedTicks);
17597  Utilities->SaveFileInt(ErrorFile, TotalTicks);
17598 
17599 // save call stack
17600  Utilities->SaveFileString(ErrorFile, "***Call stack***");
17601  for(unsigned int x = 0; x < Utilities->CallLog.size(); x++)
17602  {
17603  AnsiString Item = Utilities->CallLog.at(x);
17604  ErrorFile << Item.c_str() << '\n';
17605  }
17606 // save event log
17607  Utilities->SaveFileString(ErrorFile, "***Event log***");
17608  for(unsigned int x = 0; x < Utilities->EventLog.size(); x++)
17609  {
17610  AnsiString Item = Utilities->EventLog.at(x);
17611  ErrorFile << Item.c_str() << '\n';
17612  }
17613 // save interface
17614  Utilities->SaveFileString(ErrorFile, "***Interface***");
17615  SaveInterface(1, ErrorFile);
17616 // save track elements
17617  Utilities->SaveFileString(ErrorFile, "***Track***");
17618  if(Track->UserGraphicVector.empty())
17619  {
17620  Track->SaveTrack(2, ErrorFile, false); // false for no graphics (**Active elements** saved as marker)
17621  }
17622  else
17623  {
17624  Track->SaveTrack(12, ErrorFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
17625  }
17626 // save text elements
17627  Utilities->SaveFileString(ErrorFile, "***Text***");
17628  TextHandler->SaveText(3, ErrorFile);
17629 // save ConstructPrefDir PrefDirVector elements
17630  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir PrefDirVector***");
17631  ConstructPrefDir->SavePrefDirVector(7, ErrorFile);
17632 // save ConstructPrefDir SearchVector elements
17633  Utilities->SaveFileString(ErrorFile, "***ConstructPrefDir SearchVector***");
17634  ConstructPrefDir->SaveSearchVector(0, ErrorFile);
17635 // save EveryPrefDir elements
17636  Utilities->SaveFileString(ErrorFile, "***PrefDirs***");
17637  EveryPrefDir->SavePrefDirVector(3, ErrorFile);
17638  if(!Track->UserGraphicVector.empty())
17639  {
17640  // save user graphics
17641  Utilities->SaveFileString(ErrorFile, "***UserGraphics***");
17642  Track->SaveUserGraphics(3, ErrorFile);
17643  }
17644 // save ConstructRoute PrefDirVector
17645  Utilities->SaveFileString(ErrorFile, "***ConstructRoute PrefDirVector***");
17646  ConstructRoute->SavePrefDirVector(4, ErrorFile);
17647 // save ConstructRoute SearchVector
17648  Utilities->SaveFileString(ErrorFile, "***ConstructRoute SearchVector***");
17649  ConstructRoute->SaveSearchVector(1, ErrorFile);
17650 // save AllRoutes
17651  Utilities->SaveFileString(ErrorFile, "***Routes***");
17652  AllRoutes->SaveRoutes(1, ErrorFile);
17653 // save LockedRoutes
17654  Utilities->SaveFileString(ErrorFile, "***Locked routes***");
17656 // save ContinuationAutoSigEntries
17657  Utilities->SaveFileString(ErrorFile, "***ContinuationAutoSigEntries***");
17659 // save BarriersDownVector
17660  Utilities->SaveFileString(ErrorFile, "***BarriersDownVector***");
17661  Track->SaveSessionBarriersDownVector(1, ErrorFile);
17662 // save ChangingLCVector
17663  Utilities->SaveFileString(ErrorFile, "***ChangingLCVector***");
17664  Track->SaveChangingLCVector(0, ErrorFile);
17665 // save loaded timetable
17666  if(TimetableTitle == "")
17667  Utilities->SaveFileString(ErrorFile, "***No timetable loaded***");
17668  else
17669  {
17670  Utilities->SaveFileString(ErrorFile, "***Timetable***");
17671  if(!(SaveTimetableToSessionFile(1, ErrorFile, ErrorFileStr)))
17672  {
17673  Utilities->SaveFileString(ErrorFile, "***Loaded timetable failed to save***");
17674  }
17675  }
17676 // save editing timetable
17677  if(CreateEditTTTitle == "")
17678  Utilities->SaveFileString(ErrorFile, "***No editing timetable***");
17679  else
17680  {
17681  Utilities->SaveFileString(ErrorFile, "***Editing timetable - " + CreateEditTTTitle + "***");
17682  if(!(SaveTimetableToErrorFile(1, ErrorFile, ErrorFileStr, CreateEditTTFileName)))
17683  {
17684  Utilities->SaveFileString(ErrorFile, "***Editing timetable failed to save***");
17685  }
17686  }
17687 // save TimetableClock
17688  Utilities->SaveFileString(ErrorFile, "***TimetableClock***");
17689  Utilities->SaveFileDouble(ErrorFile, double(TrainController->TTClockTime));
17690 // save trains
17691  Utilities->SaveFileString(ErrorFile, "***Trains***");
17692  TrainController->SaveSessionTrains(1, ErrorFile);
17693 // save performance file
17694  Utilities->SaveFileString(ErrorFile, "***Performance file***");
17695  SavePerformanceFile(1, ErrorFile);
17696  Utilities->SaveFileString(ErrorFile, "***End of performance file***");
17697 // addition at v2.4.1 to save TrainController->AvHoursIntValue + any future additions
17698  Utilities->SaveFileString(ErrorFile, "***Additions after v2.3.1***");
17701  Utilities->SaveFileString(ErrorFile, "***Failed Trains***");
17702  for(unsigned int x = 0; x < TrainController->TrainVector.size(); x++)
17703  {
17705  {
17708  }
17709  }
17710  Utilities->SaveFileInt(ErrorFile, -1); // marker for end of failed trains
17711  Utilities->SaveFileString(ErrorFile, "End of file at v2.4.1");
17712 // end of v2.4.1 addition
17713 
17714  ErrorFile.close();
17715  }
17716  else
17717  {
17718  TrainController->StopTTClockMessage(6, "Error file failed to open, error log won't be saved.");
17719  }
17720  Screen->Cursor = TCursor(-2); // Arrow
17721 }
17722 
17723 // ---------------------------------------------------------------------------
17724 
17725 void TInterface::SaveTempTimetableFile(int Caller, AnsiString InFileName)
17726  // the .ttb section is delimited by '\n' followed by "***End***"
17727  // first create a .ttb file in the working folder exactly like the original
17728 
17729  // Note: this type of file use failed when used to resave timetable.tmp from temp .ttb file, but changed that to avoid so many rapid
17730  // file actions in quick succession & been OK since then, but nevertheless keep the 10 retries before giving message to be on safe side
17731 {
17732  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTempTimetableFile");
17733  if((TempTTFileName != "") && FileExists(TempTTFileName))
17734  {
17735  DeleteFile(TempTTFileName);
17736  }
17737  int TempTTFileNumber = 0;
17738 
17739  while(FileExists(CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp"))
17740  {
17741  TempTTFileNumber++;
17742  }
17743  TempTTFileName = CurDir + "\\TmpTT" + AnsiString(TempTTFileNumber) + ".tmp";
17744  int InHandle = FileOpen(InFileName, fmOpenRead);
17745  int Count = 0;
17746 
17747  while(InHandle < 0) // sometimes fails, have 10 retries before giving message
17748  {
17749  InHandle = FileOpen(InFileName, fmOpenRead);
17750  Count++;
17751  Delay(2, 50); // 50mSec delay between tries
17752  if(Count > 10)
17753  {
17754  ShowMessage("Failed to open timetable file, make sure it's not open in another application");
17755  Utilities->CallLogPop(1400);
17756  return;
17757  }
17758  }
17759  int OutHandle = FileCreate(TempTTFileName);
17760 
17761  Count = 0;
17762  while(OutHandle < 0) // sometimes fails, have 10 retries before giving message
17763  {
17764  OutHandle = FileCreate(TempTTFileName);
17765  Count++;
17766  Delay(3, 50); // 50mSec delay between tries
17767  if(Count > 10)
17768  {
17769  ShowMessage("Failed to save temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
17770  FileClose(InHandle);
17771  Utilities->CallLogPop(1401);
17772  return;
17773  }
17774  }
17775  int CountIn, CountOut;
17776  char *Buffer = new char[10000]; // can't use LoadFileString as that expects a '\0' delimiter
17777 
17778  while(true)
17779  {
17780  CountIn = FileRead(InHandle, Buffer, 10000);
17781  CountOut = FileWrite(OutHandle, Buffer, CountIn);
17782  if(CountOut != CountIn)
17783  {
17784  ShowMessage("Error in writing to the temporary timetable file, sessions can't be saved - try again, may only be a temporary problem");
17785  delete Buffer;
17786  FileClose(InHandle);
17787  FileClose(OutHandle);
17788  Utilities->CallLogPop(1402);
17789  return;
17790  }
17791  if(CountIn < 10000)
17792  break;
17793  }
17794  delete Buffer;
17795  FileClose(InHandle);
17796  FileClose(OutHandle);
17797  Utilities->CallLogPop(1403);
17798 }
17799 
17800 // ---------------------------------------------------------------------------
17801 
17802 void TInterface::SetTrackLengths(int Caller, int Distance, int SpeedLimit) // Distance & SpeedLimit are -1 for no change to that parameter
17803 /*
17804  Rules: Platforms are fixed length elements of 100m and aren't changed. Variable length elements can't be less than 20m.
17805  above changed in v2.4.0 to be variable as other track, but if <50m or >200m a warning is given
17806 
17807  Enter with DistanceVector containing the PrefDir to be set, Distance containing the required sum of all element lengths,
17808  and SpeedLimit containing the speed limit. If either of these is -1 (can be -1 separately) then no change is to be made to it.
17809  Return for an empty DistanceVector. Deal first with a single element in the vector, giving a message if there is a platform there.
17810  Now set exit link position (XLinkPos) value for the first element in DistanceVector by checking which link connects to the second
17811  element in the vector, and give a warning message if fail to find it. Now have to make two passes through the vector, firstly to
17812  sum the fixed lengths, count the number of variable length elements and set the speed limit, and secondly to set the lengths.
17813  Firstly store the first XLinkPos so don't have to recalculate it for the second pass. On the first pass examine each element,
17814  incrementing the variable element count or summing the fixed length count as go along, and setting the speed limits providing
17815  SpeedLimit isn't -1. If Distance was -1 then still go through but don't count anything, just set the speed limits. Recalculate
17816  the next XLinkPos for each succeeding element.
17817  After the first pass return if Distance was -1 as in that case have now finished. Otherwise check if the distance to be set is less than
17818  the minimum possible within the rules, and if so give a message and return. Also give a warning message if there aren't any variable length
17819  elements. Now enter the second pass. In this the length of each variable element is set to int(RemainingDistance/RemainingVarElements) and
17820  fixed length elements are ignored. After each variable length element is set the RemainingDistance and RemainingVarElements are recalculated
17821  ready for the next setting. In this way there is never more than 1 difference between any two variable length elements and the total
17822  distance sums exactly to the value required. A check is made after every variable length element has been set to see whether RemainingDistance
17823  and RemainingVarElements are zero, and if they don't reach zero together (which they should after the last variable length element has
17824  been set), an error message is given.
17825 */
17826 
17827 {
17828  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLengths," + AnsiString(Distance) + "," + AnsiString(SpeedLimit));
17829  bool FoundFlag;
17830 
17831 // ResetDistanceElements(4);
17832  if(ConstructPrefDir->PrefDirSize() == 0)
17833  {
17834  Utilities->CallLogPop(608);
17835  return;
17836  }
17837 // must have PrefDir size of at least 2
17838 
17839 // first pass to count number of variable length elements, sum fixed lengths & set speed limit
17840 // for version in v2.4.0 have no fixed length elements but leave code as is as much as possible
17841  int VarElements = 0; // FixedLength = 0; drop this in v2.4.0
17842  bool NamedLocPresent = false;
17843 
17844  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
17845  {
17846  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(167, x);
17847  TTrackElement & TE = Track->TrackElementAt(34, Track->GetVectorPositionFromTrackMap(28, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
17848  if(!FoundFlag)
17849  {
17850  throw Exception("Error - failed to find track element at " + AnsiString(TE.HLoc) + " & " + AnsiString(TE.VLoc) + " in SetLengths");
17851  }
17852  if((Distance != -1) && (!Track->IsPlatformOrNamedNonStationLocationPresent(2, TE.HLoc, TE.VLoc)))
17853  VarElements++;
17854  else if((Distance != -1) && (Track->IsPlatformOrNamedNonStationLocationPresent(3, TE.HLoc, TE.VLoc)))
17855  {
17856  VarElements++; // added in v2.4.0 for no fixed elements
17857  NamedLocPresent = true;
17858 // FixedLength+= DefaultTrackLength; dropped in v2.4.0 for no fixed elements
17859  }
17860 
17861  if((PrefDirElement.GetELinkPos() < 2) && (PrefDirElement.GetXLinkPos() < 2)) // could be points
17862  {
17863  if(SpeedLimit != -1)
17864  TE.SpeedLimit01 = SpeedLimit;
17865  }
17866  else
17867  {
17868  if(SpeedLimit != -1)
17869  TE.SpeedLimit23 = SpeedLimit;
17870  }
17871  }
17872  if(Distance == -1) // can't return before this as need to set speed limits
17873  {
17874  Utilities->CallLogPop(612);
17875  return;
17876  }
17877 
17878  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) < 50)) // these two additions are for in v2.4.0
17879  {
17880  ShowMessage("Note: Named location elements are quite short. If they are too short the simulation might depart too far from reality.");
17881  }
17882 
17883  if((NamedLocPresent) && (VarElements > 0) && ((Distance / VarElements) > 200))
17884  {
17885  ShowMessage("Note: Named location elements are quite long. If they are too long the simulation might depart too far from reality.");
17886  }
17887 
17888 /* if(NamedLocPresent) as was
17889  {
17890  ShowMessage("Named location lengths won't be changed");
17891  }
17892 */
17893 
17894  if((VarElements * 20) > Distance) // removed '+ FixedLength'
17895  {
17896  ShowMessage("Required distance is less than the minimum, will set each element to the minimum (20m)");
17897  Distance = (VarElements * 20); // removed '+ FixedLength'
17898  }
17899  if(VarElements == 0)
17900  {
17901 // ShowMessage("Unable to set distance as all elements are of fixed length"); as was
17902  ShowMessage("No elements selected"); // probably don't need this but include for safety
17903  Utilities->CallLogPop(613);
17904  return;
17905  }
17906 
17907 // second pass, set variable lengths
17908  int RemainingDistance = Distance, RemainingVarElements = VarElements, NextLength = RemainingDistance / VarElements; // removed ' - FixedLength'
17909 
17910  for(unsigned int x = 0; x < ConstructPrefDir->PrefDirSize(); x++)
17911  {
17912  TPrefDirElement PrefDirElement = ConstructPrefDir->GetFixedPrefDirElementAt(168, x);
17913  TTrackElement & TE = Track->TrackElementAt(35, Track->GetVectorPositionFromTrackMap(29, PrefDirElement.HLoc, PrefDirElement.VLoc, FoundFlag));
17914 // if(!Track->IsPlatformOrNamedNonStationLocationPresent(4, TE.HLoc, TE.VLoc)) //variable lengths dropped in v2.4.0
17915 // {
17916  if(NextLength < 20)
17917  NextLength = 20; // added for safety
17918  if(TE.TrackType == Points)
17919  {
17920  if((PrefDirElement.GetELinkPos() == 1) || (PrefDirElement.GetXLinkPos() == 1))
17921  {
17922  TE.Length01 = NextLength;
17923  }
17924  else
17925  {
17926  TE.Length23 = NextLength;
17927  }
17928  }
17929  else
17930  {
17931  if(PrefDirElement.GetELinkPos() < 2)
17932  {
17933  TE.Length01 = NextLength;
17934  }
17935  else
17936  {
17937  TE.Length23 = NextLength;
17938  }
17939  }
17940  RemainingDistance -= NextLength;
17941  RemainingVarElements--;
17942  if(RemainingVarElements > 0)
17943  NextLength = RemainingDistance / RemainingVarElements;
17944  else
17945  NextLength = 20;
17946 
17947 /* removed these as using integer division & that sometimes problematic. None of these errors ever reported but be safe
17948  if((RemainingDistance == 0) && (RemainingVarElements != 0))
17949  {
17950  throw Exception("Error RemainingDistance == 0 & RemainingVarElements != 0");
17951  }
17952  if((RemainingDistance != 0) && (RemainingVarElements == 0))
17953  {
17954  throw Exception("Error RemainingDistance != 0 & RemainingVarElements == 0");
17955  }
17956 */
17957 // }
17958  }
17959  Utilities->CallLogPop(614);
17960 }
17961 
17962 // ---------------------------------------------------------------------------
17963 
17965 {
17966  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveAsSubroutine");
17968  ShowMessage("Nothing to save!");
17969  else
17970  {
17971  if(Track->IsReadyForOperation())
17972  {
17973  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev|Railway file (*.rly)|*.rly";
17974  }
17975  else
17976  SaveRailwayDialog->Filter = "Development file (*.dev)|*.dev";
17977  if(SaveRailwayDialog->Execute())
17978  {
17979  Screen->Cursor = TCursor(-11); // Hourglass;
17980  TrainController->LogEvent("Save " + SaveRailwayDialog->FileName);
17981  AnsiString Extension = "";
17982  if(SaveRailwayDialog->FileName.Length() > 2)
17983  {
17984  Extension = AnsiString(SaveRailwayDialog->FileName).SubString(AnsiString(SaveRailwayDialog->FileName).Length() - 2, 3).UpperCase();
17985  }
17986  if((Extension == "DEV") || (Track->IsReadyForOperation() && (Extension == "RLY")))
17987  {
17988  std::ofstream VecFile(AnsiString(SaveRailwayDialog->FileName).c_str());
17989  if(!(VecFile.fail()))
17990  {
17994  // save track elements
17995  if(Track->UserGraphicVector.empty())
17996  {
17997  Track->SaveTrack(1, VecFile, false); // false for no graphics (**Active elements** saved as marker)
17998  }
17999  else
18000  {
18001  Track->SaveTrack(13, VecFile, true); // true for graphics to be saved (**Active elements**1 saved as marker)
18002  }
18003  // save text elements
18004  TextHandler->SaveText(1, VecFile);
18005  // save PrefDir elements
18006  EveryPrefDir->SavePrefDirVector(1, VecFile);
18007  if(!Track->UserGraphicVector.empty())
18008  {
18009  // save user graphics
18010  Track->SaveUserGraphics(4, VecFile);
18011  }
18012  VecFile.close();
18013  SavedFileName = SaveRailwayDialog->FileName; // includes the full PrefDir
18014  if(SavedFileName != "") // shouldn't be "" at this stage but leave in as a safeguard
18015  {
18016  char LastChar = SavedFileName[SavedFileName.Length()];
18017  if((LastChar == 'y') || (LastChar == 'Y'))
18018  {
18019  RlyFile = true;
18020  }
18021  else
18022  {
18023  RlyFile = false;
18024  }
18025  }
18026  else
18027  {
18028  RlyFile = false;
18029  }
18030  FileChangedFlag = false;
18031  for(int x = SaveRailwayDialog->FileName.Length(); x > 0; x--)
18032  {
18033  if(SaveRailwayDialog->FileName[x] == '\\')
18034  {
18035  RailwayTitle = SaveRailwayDialog->FileName.SubString(x + 1, SaveRailwayDialog->FileName.Length() - x - 4);
18036  // TimetableTitle = ""; leave this as is, no need to unload a tt just because saved railway
18037  SetCaption(7);
18038  break;
18039  }
18040  }
18041  Level1Mode = BaseMode;
18042  SetLevel1Mode(13); // to disable the save option
18043  } // if(!(VecFile.fail()))
18044  else
18045  ShowMessage("File open failed prior to save");
18046  } // else following if(!Track->IsReadyForOperation() && (Extension != "DEV"))
18047  else
18048  {
18049  ShowMessage("Can't save: extension must be either '.dev', or '.rly' with railway ready for operation");
18050  }
18051  Screen->Cursor = TCursor(-2); // Arrow
18052  } //if(SaveRailwayDialog->Execute())
18053  }
18054  Utilities->CallLogPop(1546);
18055 }
18056 
18057 // ---------------------------------------------------------------------------
18058 
18060 { // no need for caller or log as only setting values
18061  CutMenuItem->Visible = true;
18062  CopyMenuItem->Visible = true;
18063  FlipMenuItem->Visible = true;
18064  MirrorMenuItem->Visible = true;
18065  RotRightMenuItem->Visible = true;
18066  RotLeftMenuItem->Visible = true;
18067  RotateMenuItem->Visible = true;
18068  PasteMenuItem->Visible = true;
18069 // PasteWithAttributesMenuItem->Visible = true; //added at v2.2.0
18070  DeleteMenuItem->Visible = true;
18071  SelectLengthsMenuItem->Visible = true;
18072  ReselectMenuItem->Visible = true;
18073 
18074  CutMenuItem->Enabled = false;
18075  CopyMenuItem->Enabled = false;
18076  FlipMenuItem->Enabled = false;
18077  MirrorMenuItem->Enabled = false;
18078  RotRightMenuItem->Enabled = false;
18079  RotLeftMenuItem->Enabled = false;
18080  RotateMenuItem->Enabled = false;
18081  PasteMenuItem->Enabled = false;
18082 // PasteWithAttributesMenuItem->Enabled = false; //new at v2.2.0
18083  DeleteMenuItem->Enabled = false;
18084  SelectLengthsMenuItem->Enabled = false;
18085  if(SelectionValid)
18086  ReselectMenuItem->Enabled = true;
18087  else
18088  ReselectMenuItem->Enabled = false;
18089 
18090  SelectBiDirPrefDirsMenuItem->Visible = false;
18091  CancelSelectionMenuItem->Enabled = true;
18092  SelectMenuItem->Enabled = true;
18093 
18094  if(NoRailway())
18095  {
18096  EditMenu->Enabled = false;
18097  }
18098  else
18099  EditMenu->Enabled = true;
18100 }
18101 
18102 // ---------------------------------------------------------------------------
18103 
18105 { // no need for caller or log as only setting values
18106  EditMenu->Enabled = true;
18107 
18108  CutMenuItem->Visible = false;
18109  CopyMenuItem->Visible = false;
18110  FlipMenuItem->Visible = false;
18111  MirrorMenuItem->Visible = false;
18112  RotRightMenuItem->Visible = false;
18113  RotLeftMenuItem->Visible = false;
18114  RotateMenuItem->Visible = false;
18115  PasteMenuItem->Visible = false;
18116 // PasteWithAttributesMenuItem->Visible = false; //added at v2.2.0
18117  DeleteMenuItem->Visible = false;
18118  SelectLengthsMenuItem->Visible = false;
18119  ReselectMenuItem->Visible = false;
18120 
18121  SelectBiDirPrefDirsMenuItem->Visible = true;
18122  SelectBiDirPrefDirsMenuItem->Enabled = false;
18123  CancelSelectionMenuItem->Enabled = true;
18124  SelectMenuItem->Enabled = true;
18125 }
18126 
18127 // ---------------------------------------------------------------------------
18128 
18130 {
18131  return ((Track->NoActiveOrInactiveTrack(5)) && (TextHandler->TextVectorSize(8) == 0) && Track->UserGraphicVector.empty());
18132 }
18133 
18134 // ---------------------------------------------------------------------------
18135 
18137 {
18138  SelectRect.left = 0;
18139  SelectRect.right = 0;
18140  SelectRect.top = 0;
18141  SelectRect.bottom = 0;
18142 }
18143 
18144 // ---------------------------------------------------------------------------
18145 
18146 bool TInterface::EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
18147 { // return position of erased name in HPos & VPos, return true for found & erased
18148  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationNameText," + Name);
18149  bool TextFound = false;
18150 
18151 // if(Track->LocationNameMultiMap.find(Name) == Track->LocationNameMultiMap.end()) {} //name not in LocationNameMultiMap, so don't erase from TextVector //condition dropped at v1.1.4 because of change in EnterLocationNames
18152 /* else */ if(TextHandler->FindText(0, Name, HPos, VPos))
18153  {
18154  if(TextHandler->TextErase(4, HPos, VPos, Name))
18155  {;
18156  } // condition not used
18157  TextFound = true;
18158  }
18159  Utilities->CallLogPop(1956);
18160  return TextFound;
18161 }
18162 
18163 // ---------------------------------------------------------------------------
18164 
18165 void TInterface::AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
18166 {
18167  if(Name == "")
18168  {
18169  return;
18170  }
18171  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddLocationNameText," + Name + "," + AnsiString(HPos) + "," +
18172  AnsiString(VPos) + "," + AnsiString((short)UseEnteredPosition));
18173  int VPosHi, VPosLo, TextPosHi, TextPosLo;
18174  TFont *Font = Display->GetFont();
18175 
18176  if(!UseEnteredPosition)
18177  {
18178  if(!Track->FindHighestLowestAndLeftmostNamedElements(0, Name, VPosHi, VPosLo, HPos))
18179  {
18180  Utilities->CallLogPop(1561);
18181  return;
18182  }
18183  int Depth = abs(Font->Height); // Height may be negative - see C++Builder Help file
18184  TextPosHi = VPosHi + 20; // add depth of track element + 4 pixels
18185  TextPosLo = VPosLo - Depth - 4; // reduce by depth of font + 4 pixels
18186  int ScreenPosHi = (Display->DisplayOffsetV * 16) + 576;
18187  int ScreenPosLo = Display->DisplayOffsetV * 16;
18188  if(TextPosLo >= ScreenPosLo)
18189  VPos = TextPosLo; // if Lo value on screen then use that - displays above the location
18190  else if(TextPosHi < ScreenPosHi)
18191  VPos = TextPosHi;
18192  else
18193  VPos = ScreenPosLo + 288; // if location extends to or beyond height of screen the display in centre of screen
18194  }
18195  TTextItem TI(HPos, VPos, Name, Font);
18196 
18197  TI.Font = Font; // may have been changed in constructor when returned as reference
18198  TextHandler->EnterAndDisplayNewText(1, TI, HPos, VPos);
18199  Utilities->CallLogPop(1558);
18200 }
18201 
18202 // ---------------------------------------------------------------------------
18203 
18205 {
18206  try
18207  {
18208 /*
18209  ShowMessage(
18210  "Interface->Left + Interface->Width " + UnicodeString(Interface->Left + Interface->Width) +
18211  "\nInterface->Left + MainScreen->Left + MainScreen->Width " +
18212  UnicodeString(Interface->Left + MainScreen->Left + MainScreen->Width) +
18213  "\n\nMainScreen->Width " + UnicodeString(MainScreen->Width) +
18214  "\nMainScreen->Height " + UnicodeString(MainScreen->Height) +
18215  "\nMainScreen->Top " + UnicodeString(MainScreen->Top) +
18216  "\nMainScreen->Left " + UnicodeString(MainScreen->Left) +
18217  " Right " + UnicodeString(MainScreen->Width + MainScreen->Left) +
18218  "\n\nInterface->Width " + UnicodeString(Interface->Width) +
18219  "\nInterface->Left " + UnicodeString(Interface->Left) +
18220  "\nInterface->Top " + UnicodeString(Interface->Top) +
18221  "\n\nScreenRightButton->Left " + UnicodeString(ScreenRightButton->Left)
18222  );
18223 */
18224 /*
18225  for(unsigned int x=0; x<TrainController->TrainVector.size(); x++)
18226  {
18227  if((TrainController->TrainVectorAt(-1, x).HeadCode == "2K02") && (!TrainController->TrainVectorAt(-1, x).TrainOnContinuation(-1)))
18228  {
18229  TrainController->TrainVectorAt(-1, x).TrainFailurePending = true;
18230  }
18231  }
18232 */
18233 
18234 // throw Exception("Test error"); //generate an error file
18235 
18236 // ShowMessage("MissedTicks = " + AnsiString(MissedTicks) + "; TotalTicks = " + AnsiString(TotalTicks));
18237 
18238  }
18239  catch(const Exception &e)
18240  {
18241  ErrorLog(114, e.Message);
18242  }
18243 }
18244 
18245 // ---------------------------------------------------------------------------
18246 /*
18247  void TInterface::LoadNormalSignalGlyphs(int Caller) //changed - see below
18248  {
18249  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
18250  SpeedButton68->Glyph->LoadFromResourceName(0, "gl68"); SpeedButton69->Glyph->LoadFromResourceName(0, "gl69");
18251  SpeedButton70->Glyph->LoadFromResourceName(0, "gl70"); SpeedButton71->Glyph->LoadFromResourceName(0, "gl71");
18252  SpeedButton72->Glyph->LoadFromResourceName(0, "gl72"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73");
18253  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74"); SpeedButton75->Glyph->LoadFromResourceName(0, "gl75");
18254  Utilities->CallLogPop(**);
18255  }
18256 
18257  //---------------------------------------------------------------------------
18258 
18259  void TInterface::LoadGroundSignalGlyphs(int Caller) //changed - see below
18260  {
18261  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
18262  SpeedButton68->Glyph->LoadFromResourceName(0, "bm68grounddblred"); SpeedButton69->Glyph->LoadFromResourceName(0, "bm69grounddblred");
18263  SpeedButton70->Glyph->LoadFromResourceName(0, "bm70grounddblred"); SpeedButton71->Glyph->LoadFromResourceName(0, "bm71grounddblred");
18264  SpeedButton72->Glyph->LoadFromResourceName(0, "bm72grounddblred"); SpeedButton73->Glyph->LoadFromResourceName(0, "gl73grounddblred");
18265  SpeedButton74->Glyph->LoadFromResourceName(0, "gl74grounddblred"); SpeedButton75->Glyph->LoadFromResourceName(0, "bm75grounddblred");
18266  Utilities->CallLogPop(**);
18267  }
18268 */
18269 // ---------------------------------------------------------------------------
18270 void TInterface::LoadNormalSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
18271 {
18272  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadNormalSignalGlyphs,");
18281  Utilities->CallLogPop(1871);
18282 }
18283 
18284 // ---------------------------------------------------------------------------
18285 
18286 void TInterface::LoadGroundSignalGlyphs(int Caller) // changed from the above at v2.3.0 so the signal glyphs change hands
18287 {
18288  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGroundSignalGlyphs,");
18297  Utilities->CallLogPop(1872);
18298 }
18299 
18300 // ---------------------------------------------------------------------------
18301 
18302 void TInterface::UpdateOperatorActionPanel(int Caller) // new at v2.2.0
18303  // limit it to 20 entries max
18304 {
18305  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UpdateOperatorActionPanel");
18307  {
18308  OAListBox->Clear();
18309  }
18311  // new at v2.2.0
18312  {
18313  Utilities->CallLogPop(2092);
18314  return;
18315  }
18316  AnsiString OpTimeToActDisplay;
18317  AnsiString OpTimeToActString;
18318  AnsiString HeadCode;
18319  float OpTimeToActFloat;
18320  TTrainController::THCandTrainPosParam HCandTrainPosParam;
18321 
18324  {
18325  if(OAListBox->Items->Count >= 20)
18326  {
18327  break;
18328  }
18329  OpTimeToActFloat = TrainController->OpTimeToActMultiMapIterator->first;
18330  HCandTrainPosParam = TrainController->OpTimeToActMultiMapIterator->second;
18331  HeadCode = HCandTrainPosParam.first;
18332  if(OpTimeToActFloat < 0.25) // 15 secs estimated
18333  {
18334  OpTimeToActString = "NOW";
18335  }
18336  else if(OpTimeToActFloat < 1)
18337  {
18338  OpTimeToActString = "<1";
18339  }
18340  else
18341  {
18342  OpTimeToActString = AnsiString(floor(OpTimeToActFloat));
18343  }
18344  if(OpTimeToActFloat < 60)
18345  {
18346  OpTimeToActDisplay = HeadCode + AnsiString('\t') + OpTimeToActString;
18347  OAListBox->Items->Add(OpTimeToActDisplay); // original
18348  }
18350  }
18351  Utilities->CallLogPop(2093);
18352 }
18353 
18354 // ---------------------------------------------------------------------------
18355 
18356 void TInterface::LoadUserGraphic(int Caller) // new at v2.4.0
18357 {
18358  try
18359  {
18360  TrainController->LogEvent("LoadUserGraphic");
18361  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadUserGraphic");
18363  if(LoadUserGraphicDialog->Execute())
18364  {
18365  TrainController->LogEvent("LoadUserGraphic " + LoadUserGraphicDialog->FileName);
18366  SelectedGraphicFileName = AnsiString(LoadUserGraphicDialog->FileName); // SelectedGraphicFileName is a class member
18368  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.find(SelectedGraphicFileName);
18369  if(UGMIt == Track->UserGraphicMap.end()) // i.e. there isn't an entry for that filename so insert one, else take no action
18370  {
18371  UGME.first = SelectedGraphicFileName;
18372  TPicture *PicPtr = new TPicture;
18373  PicPtr->LoadFromFile(SelectedGraphicFileName);
18374  UGME.second = PicPtr;
18375  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
18376  {
18377  throw Exception("Map Insertion Error 1 - UserGraphicMap insertion failure for " + SelectedGraphicFileName);
18378  }
18379  }
18381  SetLevel2TrackMode(65);
18382  }
18383  Utilities->CallLogPop(2191);
18384  }
18385  catch(const EInvalidGraphic &e)
18386  {
18387  ShowMessage(
18388  "Incorrect file format, the file can't be loaded.\nEnsure that the file you want is a valid graphic file with extension .bmp, .gif, .jpg, or .png");
18389  }
18390  catch(const Exception &e)
18391  {
18392  ErrorLog(215, e.Message);
18393  }
18394 }
18395 
18396 // ---------------------------------------------------------------------------
18397 /*
18398  Problems with ifstream reading (see 'SessionFileIntegrityCheck(AnsiString FileName)' above):-
18399 
18400  These problems were with Borland C++Builder 4.
18401 
18402  The functions saved in OldFiles\Backups220809Duringifstream testing were used for testing the odd behaviour where the
18403  ifstream pointer gave different characters using get() and getline(), when reading the timetable entries in the session
18404  file for 20/08/09 at 18:45 (saved). All was well until point 48677 in the session file, when for some reason the
18405  getline(0 & get(0 gave different results. Many earlier timetable strings had been read OK before that, and it wasn't
18406  clear what was special about this particular string.
18407  Later more detailed study found that on reading the string beginning at point 48605 (i.e. the one earlier than above),
18408  within function CheckNoNewLineAtStartNonZeroTerminatedFileString the file pointer (using tellg()) reduced from 48606 to
18409  48604 after reading the 'F' character. Thereafter characters were read correctly but the pointer remained 2 too low.
18410  This is thought to be a flaw in the compiler.
18411  Later again additional tellg()s and a seekg()s were included in CheckNoNewLineAtStartNonZeroTerminatedFileString, and
18412  though these should have had no effect they somehow caused the next getline() within CheckTimetableFromSessionFile to
18413  read a null, even though the pointer had been reset to its value before the call to
18414  CheckNoNewLineAtStartNonZeroTerminatedFileString. Again this seems to be a flaw in the compiler, where the pointer
18415  that is indicated by tellg and the true pointer within the system can be different.
18416  Tried the old c++ stream library to see if that worked but it was exactly the same. Probably because the same code is
18417  used for both with the new library just defined within the std namespace.
18418  Success!! Traced to the putback function failing. It (apparently) can't be used if the file pointer has been altered
18419  after the last read that is to be put back. Corrected that & the most recent session file checked out & loaded OK.
18420  (note - don't need the ifstream file to be open in output mode for the putback to work)
18421  But: the earlier file - 18:45 as above - still fails to advance the file pointer in the middle of checking the
18422  timetable, it sticks at position 48601. This position points to 'r' in 'Frh' just before a newline. Also the file
18423  integrity is OK up to and after this sticking point. Oddly though the loading function works fine (i.e. by bypassing
18424  the integrity check function), though the timetable isn't read directly, it is copied to a new stand-alone timetable
18425  file and that read by the program.
18426  Created a new version of CheckNoNewLineAtStartNonZeroTerminatedFileString with 'New' at end, & got rid of all the
18427  internal digressions & getlines. This passed the earlier sticking point, but stuck later at 48677, i.e. the 'h' from
18428  'Frh' at the end of the entry following that for the earlier sticking point. Here
18429  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew works fine, with end pointer correctly set at 48680, i.e. after the
18430  newline, but the subsequent getline() function, although it retrieves the line correctly, the file pointer is set to
18431  48677, i.e. before the newline, so getline seems to fail to extract the newline character. Still to check - why doesn't
18432  CheckNoNewLineAtStartNonZeroTerminatedFileStringNew see 'h' instead of '0' in the subsequent read? If it did the two
18433  would tally, though would still be wrong.
18434  Further investigation:- CheckNoNewLineAtStartNonZeroTerminatedFileStringNew doesn't seem to recognize the file pointer
18435  as set by seekg at 48677. It continues to read at the point it left off earlier, whereas getline() does read at 48677
18436  & recovers 'h'. Continuing to apply getline() after the above effect it is found that it doesn't extract newlines after
18437  reading further lines, but extracts them when read alone i.e. it reads a line then a null in succession, although the
18438  lines are only separated by single newline characters.
18439 
18440  Need to check:
18441  1. Does the file read correctly if only get() functions used without getline() and without resetting the file pointer?
18442  2. Does the file read correctly if only getline() functions used without get() and without resetting the file pointer?
18443  3. Does the file read correctly if get() functions alternated with getline() but without resetting the file pointer?
18444 
18445  For 1: Still goes wrong at usual place, reads 'h' at the same point. Try not resetting the file pointer with seekg.
18446  Tried this - got past the earlier point but failed later with a reduction in file pointer after a character read. In
18447  fact the reduction was by 40 bytes for reading a single comma! Try without any tellg's - yes, that got past all the
18448  timetable OK. So, works OK with just get() providing no tellg's (& no seekg's).
18449 
18450  For 2: Works OK using getline().
18451 
18452  For 3: Gets to end of timetable OK but the next tellg gives a wrong value. Check if using getline() alone gives a
18453  wrong tellg. Tried getline() alone, reached end of TT as before, but gave the same wrong file pos on using tellg.
18454  Try continuing to see if works OK in spite of tellg giving wrong result. Yes it works OK. Hence the problem seems to
18455  be tellg, which sometimes returns wrong results, and they corrupt things when used in seekg.
18456 
18457  Overall conclusion: Avoid all tellg's & seekg's. If need to reset a file position then close and reopen it.
18458 */
18459 
18460 // ---------------------------------------------------------------------------
18461 
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:15677
TInterface::SpeedButton59
TSpeedButton * SpeedButton59
Definition: InterfaceUnit.h:562
TInterface::CopyTTEntryButtonClick
void __fastcall CopyTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3530
TInterface::CtrlKey
bool CtrlKey
true when the CTRL key is pressed (see also ShiftKey)
Definition: InterfaceUnit.h:932
TInterface::MTBFEditBox
TEdit * MTBFEditBox
Definition: InterfaceUnit.h:480
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:9793
TInterface::ScreenLeftButtonClick
void __fastcall ScreenLeftButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8215
TInterface::ExitMenuItem
TMenuItem * ExitMenuItem
Definition: InterfaceUnit.h:416
TTrain::AllowedToPassRedSignal
bool AllowedToPassRedSignal
set when train has been called on, or when under signaller control and instructed to pass a red signa...
Definition: TrainUnit.h:339
TInterface::TextMoveVPos
int TextMoveVPos
used to store the original text 'H' & 'V' positions for use during text moving
Definition: InterfaceUnit.h:1089
TInterface::OperMode
@ OperMode
Definition: InterfaceUnit.h:850
TTrain::ZeroPowerNoNewShuttleFromNonRepeatMessage
bool ZeroPowerNoNewShuttleFromNonRepeatMessage
Definition: TrainUnit.h:306
TInterface::SpeedButton140
TSpeedButton * SpeedButton140
Definition: InterfaceUnit.h:643
TTrain::ZeroPowerNoNewServiceMessage
bool ZeroPowerNoNewServiceMessage
Definition: TrainUnit.h:305
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:9766
TInterface::AddPrefDirButton
TBitBtn * AddPrefDirButton
Definition: InterfaceUnit.h:115
TInterface::RemoveTrainMenuItem
TMenuItem * RemoveTrainMenuItem
Definition: InterfaceUnit.h:466
TInterface::LocationNamesSetImage
TImage * LocationNamesSetImage
Definition: InterfaceUnit.h:277
TInterface::SpeedLimitBox
TEdit * SpeedLimitBox
distance/speed setting edit box that accepts speed limits
Definition: InterfaceUnit.h:91
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TInterface::SaveImageAndGridMenuItemClick
void __fastcall SaveImageAndGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2517
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TTrainController
Handles all train and timetable activities, only one object created.
Definition: TrainUnit.h:630
TInterface::FloatingInfoMenu
TMenuItem * FloatingInfoMenu
Definition: InterfaceUnit.h:442
TInterface::SpeedButton34
TSpeedButton * SpeedButton34
Definition: InterfaceUnit.h:537
TInterface::NewTTEntryKeyFlag
bool NewTTEntryKeyFlag
Definition: InterfaceUnit.h:1011
TInterface::ConflictAnalysisButtonClick
void __fastcall ConflictAnalysisButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12173
TInterface::CallingOnButton
TSpeedButton * CallingOnButton
Definition: InterfaceUnit.h:204
TInterface::BuildTrainDataVectorForValidateFile
bool BuildTrainDataVectorForValidateFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway)
Check the integrity of a stored timetable file (either as a stand alone file or within a session file...
Definition: InterfaceUnit.cpp:16775
TInterface::SpeedButton42
TSpeedButton * SpeedButton42
Definition: InterfaceUnit.h:545
TInterface::SelectBitmapMouseLocX
int SelectBitmapMouseLocX
when flag SelectPickedUp is set to true (see above - to allow a selected screen area to move during M...
Definition: InterfaceUnit.h:1065
TInterface::PrefDirPanel
TPanel * PrefDirPanel
'Set preferred directions' panel
Definition: InterfaceUnit.h:358
TInterface::PrefDirPanelLabel
TLabel * PrefDirPanelLabel
label to the left of PrefDirPanel
Definition: InterfaceUnit.h:304
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:11248
TInterface::MTBFEditBoxKeyUp
void __fastcall MTBFEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11988
TInterface::TrackMode
@ TrackMode
Definition: InterfaceUnit.h:850
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:12337
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1573
TInterface::SaveSessionButton
TBitBtn * SaveSessionButton
Definition: InterfaceUnit.h:200
TInterface::TTLabel2
TLabel * TTLabel2
Definition: InterfaceUnit.h:339
TInterface::TTClockx1ButtonClick
void __fastcall TTClockx1ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11591
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:182
TInterface::LengthConversionPanel
TPanel * LengthConversionPanel
Definition: InterfaceUnit.h:104
TInterface::SpeedButton143
TSpeedButton * SpeedButton143
Definition: InterfaceUnit.h:646
TInterface::ChangeDirectionMenuItem
TMenuItem * ChangeDirectionMenuItem
Definition: InterfaceUnit.h:461
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:6324
TTrain::MidEntryPos
int MidEntryPos
Definition: TrainUnit.h:327
TTrainController::RebuildOpTimeToActMultimap
void RebuildOpTimeToActMultimap(int Caller)
new v2.2.0 for OperatorActionPanel
Definition: TrainUnit.cpp:17186
TTrainController::PwrHigh
bool PwrHigh
Definition: TrainUnit.h:733
TInterface::StepForwardMenuItem
TMenuItem * StepForwardMenuItem
Definition: InterfaceUnit.h:464
TTrack::SelectGraphicVector
TUserGraphicVector SelectGraphicVector
Definition: TrackUnit.h:701
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:90
SignallerMoveForwards
@ SignallerMoveForwards
Definition: TrainUnit.h:50
TInterface::SignallerControlStopMenuItem
TMenuItem * SignallerControlStopMenuItem
Definition: InterfaceUnit.h:465
TRailGraphics::ConvertSignalsToOppositeHand
void ConvertSignalsToOppositeHand(int Caller)
Converts all signal graphics to opposite hand new at v2.3.0.
Definition: GraphicUnit.cpp:4265
TInterface::FormResize
void __fastcall FormResize(TObject *Sender)
Definition: InterfaceUnit.cpp:11842
TInterface::SpeedButton70
TSpeedButton * SpeedButton70
Definition: InterfaceUnit.h:573
TInterface::SpeedButton144
TSpeedButton * SpeedButton144
Definition: InterfaceUnit.h:647
TInterface::SpeedButton32
TSpeedButton * SpeedButton32
Definition: InterfaceUnit.h:535
TInterface::SaveTTAsButtonClick
void __fastcall SaveTTAsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3994
TInterface::SelectBitmapHLoc
int SelectBitmapHLoc
the original (prior to moving & after finished moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1063
TInterface::OperatorActionButton
TBitBtn * OperatorActionButton
Definition: InterfaceUnit.h:201
TInterface::DistanceKey
TImage * DistanceKey
information panel displayed when setting distances & speed limits
Definition: InterfaceUnit.h:267
AboutUnit.h
Arrive
@ Arrive
Definition: TrainUnit.h:49
TInterface::OperatorActionPanelDragStartX
int OperatorActionPanelDragStartX
mouse 'X' position when the OperatorActionPanel begins to be dragged
Definition: InterfaceUnit.h:1051
TInterface::SpeedButton54
TSpeedButton * SpeedButton54
Definition: InterfaceUnit.h:557
TInterface::StartWholeRailwayMoveVPos
int StartWholeRailwayMoveVPos
mouse Y position when start to move the whole railway
Definition: InterfaceUnit.h:1075
TTrain::ZeroPowerNoCDTMessage
bool ZeroPowerNoCDTMessage
Definition: TrainUnit.h:304
TTrain::CallingOnFlag
bool CallingOnFlag
calling on permitted
Definition: TrainUnit.h:345
TInterface::UnrestrictedButton
TBitBtn * UnrestrictedButton
Definition: InterfaceUnit.h:196
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:702
TRailGraphics::SpeedBut72NormBlackGlyph
Graphics::TBitmap * SpeedBut72NormBlackGlyph
Definition: GraphicUnit.h:1041
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:11288
TInterface::ExportTTMenuItemClick
void __fastcall ExportTTMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2924
TInterface::RestoreTTKeyFlag
bool RestoreTTKeyFlag
Definition: InterfaceUnit.h:1017
TInterface::CancelSelectionMenuItemClick
void __fastcall CancelSelectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9480
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3544
TInterface::PERFLOG_DIR_NAME
static const UnicodeString PERFLOG_DIR_NAME
Definition: InterfaceUnit.h:863
TInterface::WholeRailwayMoving
bool WholeRailwayMoving
true when moving the railway with the mouse, new at v2.1.0
Definition: InterfaceUnit.h:996
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:13752
TInterface::TextFoundFlag
bool TextFoundFlag
indicates that a text item has been found when clicking on a build screen during 'AddText' or 'MoveTe...
Definition: InterfaceUnit.h:976
TInterface::DisableRouteButtons
void DisableRouteButtons(int Caller)
Called during operation whenever the route type buttons need to be disabled, e.g. when paused.
Definition: InterfaceUnit.cpp:17520
TInterface::OperateRailwayMenuItemClick
void __fastcall OperateRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1936
TInterface::DerailImage
TImage * DerailImage
Definition: InterfaceUnit.h:263
TTrain::MaxRunningSpeed
double MaxRunningSpeed
the current maximum train running speed
Definition: TrainUnit.h:383
TInterface::TTLabel3
TLabel * TTLabel3
Definition: InterfaceUnit.h:340
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:685
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:289
TRailGraphics::SpeedBut75NormBlackGlyph
Graphics::TBitmap * SpeedBut75NormBlackGlyph
Definition: GraphicUnit.h:1044
RestoreTimetableControl
@ RestoreTimetableControl
Definition: TrainUnit.h:50
TInterface::TTSelectedEntry
AnsiString TTSelectedEntry
used to record the current timetable entry when changing to AZ order or back to original order
Definition: InterfaceUnit.h:919
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TAllRoutes::AutoSigsRoute
@ AutoSigsRoute
Definition: TrackUnit.h:1503
TInterface::SpeedButton19
TSpeedButton * SpeedButton19
Definition: InterfaceUnit.h:522
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5064
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5091
TActionVectorEntry::LocationType
TTimetableLocationType LocationType
indicates where the train is when the relevant action occurs
Definition: TrainUnit.h:112
TInterface::MasterClockTimer
void __fastcall MasterClockTimer(TObject *Sender)
Definition: InterfaceUnit.cpp:7548
TTrack::GapFlashGreenPosition
int GapFlashGreenPosition
Definition: TrackUnit.h:669
TInterface::MainScreen
TImage * MainScreen
the railway display screen
Definition: InterfaceUnit.h:284
TInterface::SpeedButton67
TSpeedButton * SpeedButton67
Definition: InterfaceUnit.h:570
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:64
TInterface::CutMenuItem
TMenuItem * CutMenuItem
Definition: InterfaceUnit.h:431
TInterface::SpeedButton120
TSpeedButton * SpeedButton120
Definition: InterfaceUnit.h:623
TInterface::LCResetCounter
unsigned int LCResetCounter
count up to 20 then resets - to check LCs & raise barriers if no route & no train present
Definition: InterfaceUnit.h:1037
TInterface::BlueBgndMenuItem
TMenuItem * BlueBgndMenuItem
Definition: InterfaceUnit.h:426
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1645
TInterface::TTLabel1
TLabel * TTLabel1
Definition: InterfaceUnit.h:338
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:8765
TInterface::ResetChangedFileDataAndCaption
void ResetChangedFileDataAndCaption(int Caller, bool NonPrefDirChangesMade)
Called whenever the railway is changed to deal with title displays (loaded railway and timetable) and...
Definition: InterfaceUnit.cpp:15629
TTrain::MaxBrakeRate
double MaxBrakeRate
the maximum brake rate that the train can achieve
Definition: TrainUnit.h:387
TInterface::SpeedButton52
TSpeedButton * SpeedButton52
Definition: InterfaceUnit.h:555
TInterface::IMAGE_DIR_NAME
static const UnicodeString IMAGE_DIR_NAME
Definition: InterfaceUnit.h:865
TInterface::ShowPerformancePanel
bool ShowPerformancePanel
true when the 'show performance panel' button has been clicked during operation
Definition: InterfaceUnit.h:970
TInterface::LoadSessionDialog
TOpenDialog * LoadSessionDialog
Definition: InterfaceUnit.h:488
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TInterface::OutputLog10MouseDown
void __fastcall OutputLog10MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10929
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:523
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2449
TInterface::SpeedButton116
TSpeedButton * SpeedButton116
Definition: InterfaceUnit.h:619
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5220
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:149
TTrain::MidExitPos
int MidExitPos
Definition: TrainUnit.h:327
TInterface::NewSelectBitmapVLoc
int NewSelectBitmapVLoc
as above for VLoc
Definition: InterfaceUnit.h:1049
TInterface::MoveTextOrGraphic
@ MoveTextOrGraphic
Definition: InterfaceUnit.h:880
TInterface::ScreenGridButton
TBitBtn * ScreenGridButton
Definition: InterfaceUnit.h:71
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:6967
TInterface::EditMenu
TMenuItem * EditMenu
Definition: InterfaceUnit.h:428
TTrain::TrainFailed
bool TrainFailed
added at v2.4.0 to indicate failure
Definition: TrainUnit.h:369
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:384
DisplayUnit.h
TInterface::ResetSelectRect
void ResetSelectRect()
SelectRect is the rectangle selected via the 'Edit'menu, and this function sets left,...
Definition: InterfaceUnit.cpp:18136
TInterface::TTClockAdjustWarningHide
bool TTClockAdjustWarningHide
true if user opts not to show the timetable clock adjustment warning (false on starting the program)
Definition: InterfaceUnit.h:978
TInterface::TTLabel9
TLabel * TTLabel9
Definition: InterfaceUnit.h:346
TTrain::ZeroPowerNoFrontSplitMessage
bool ZeroPowerNoFrontSplitMessage
Definition: TrainUnit.h:300
TTrainController::SPADWarning
bool SPADWarning
Definition: TrainUnit.h:722
TInterface::TTClockAdjustCheckBox
TCheckBox * TTClockAdjustCheckBox
Definition: InterfaceUnit.h:228
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:11045
TInterface::TrackNotLinkedImage
TImage * TrackNotLinkedImage
Definition: InterfaceUnit.h:274
TTrain::DepartureTimeSet
bool DepartureTimeSet
set when stopped at a location and the next action is departure (set in UpdateTrain when ReleaseTime ...
Definition: TrainUnit.h:347
TInterface::WarningHover
bool WarningHover
true when mouse hovers over warning messages during operation - to prevent clicking while changing
Definition: InterfaceUnit.h:994
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:6470
TInterface::SaveTTAsButton
TButton * SaveTTAsButton
Definition: InterfaceUnit.h:145
TInterface::ZoomButtonClick
void __fastcall ZoomButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8452
TInterface::SpeedButton90
TSpeedButton * SpeedButton90
Definition: InterfaceUnit.h:593
TTrain::LagElement
int LagElement
Definition: TrainUnit.h:327
TTrack::GetLocationName
AnsiString GetLocationName(unsigned int InactiveTrackVectorPosition)
Return location name for a given inactive track vector position.
Definition: TrackUnit.h:716
TTrainController::BufferAttentionWarning
bool BufferAttentionWarning
Definition: TrainUnit.h:722
TInterface::ExitTrackButtonClick
void __fastcall ExitTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1628
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:8519
TInterface::SpeedButton135
TSpeedButton * SpeedButton135
Definition: InterfaceUnit.h:638
TInterface::SpeedButton111
TSpeedButton * SpeedButton111
Definition: InterfaceUnit.h:614
TInterface::RouteCancelFlag
bool RouteCancelFlag
true when route cancel button pressed, enables a right mouse click to cancel a route if in an appropr...
Definition: InterfaceUnit.h:956
TTextHandler::LoadText
void LoadText(int Caller, std::ifstream &VecFile)
load the railway's text from VecFile
Definition: TextUnit.cpp:281
TInterface::SpeedToggleButton2Click
void __fastcall SpeedToggleButton2Click(TObject *Sender)
Definition: InterfaceUnit.cpp:11116
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:12138
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:13863
TInterface::LoadNormalSignalGlyphs
void LoadNormalSignalGlyphs(int Caller)
In trackbuild display normal signal types on signal buttons.
Definition: InterfaceUnit.cpp:18270
TInterface::MainScreenMouseDown3
void MainScreenMouseDown3(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-out mode.
Definition: InterfaceUnit.cpp:6905
TInterface::TTLabel11
TLabel * TTLabel11
Definition: InterfaceUnit.h:347
TInterface::CancelTTEntryButton
TButton * CancelTTEntryButton
Definition: InterfaceUnit.h:136
TInterface::SpeedButton8
TSpeedButton * SpeedButton8
Definition: InterfaceUnit.h:511
TInterface::UserGraphicVectorNumber
int UserGraphicVectorNumber
used to store a single item of user graphics
Definition: InterfaceUnit.h:1091
TInterface::PreviousTTEntryButton
TButton * PreviousTTEntryButton
Definition: InterfaceUnit.h:127
TInterface::TrackElementPanel
TPanel * TrackElementPanel
panel containing the track/location/parapet element buttons
Definition: InterfaceUnit.h:375
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:16474
TInterface::SelectionValid
bool SelectionValid
true when an area of screen has been selected via the 'Edit' & 'Select' or 'Reselect' menu items
Definition: InterfaceUnit.h:962
TDisplay::InvertElement
void InvertElement(int Caller, int HPos, int VPos)
Definition: DisplayUnit.cpp:140
TInterface::OperateButtonClick
void __fastcall OperateButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1955
TInterface::WhiteBgndMenuItem
TMenuItem * WhiteBgndMenuItem
Definition: InterfaceUnit.h:424
TTrack::IsReadyForOperation
bool IsReadyForOperation()
Indicates whether or not the railway is ready for saving as a '.rly' file and for operation.
Definition: TrackUnit.h:722
TInterface::ContinuationAutoSignals
void ContinuationAutoSignals(int Caller, TDateTime Now)
Deal with signal resetting on auto signal routes that extend to continuations where trains have depar...
Definition: InterfaceUnit.cpp:14086
TTrainController::CrashWarning
bool CrashWarning
Definition: TrainUnit.h:722
TInterface::LoadInterface
void LoadInterface(int Caller, std::ifstream &SessionFile)
Load the interface part of a session file.
Definition: InterfaceUnit.cpp:16059
TInterface::SpeedButton2
TSpeedButton * SpeedButton2
Definition: InterfaceUnit.h:505
TTrain::PlotTrain
void PlotTrain(int Caller, TDisplay *Disp)
Plots the train on the display in normal (zoomed-in) mode.
Definition: TrainUnit.cpp:7508
TInterface::AutoSigsFlag
bool AutoSigsFlag
true when AutoSig route building selected during operation
Definition: InterfaceUnit.h:926
TInterface::SetRouteButtonsInfoCaptionAndRouteNotStarted
void SetRouteButtonsInfoCaptionAndRouteNotStarted(int Caller)
Enables or disables the route type buttons depending on the route mode, sets the information panel me...
Definition: InterfaceUnit.cpp:17430
TInterface::MoveForwardsMenuItem
TMenuItem * MoveForwardsMenuItem
Definition: InterfaceUnit.h:462
TInterface::YardEdit
TEdit * YardEdit
Definition: InterfaceUnit.h:99
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3249
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:3990
TInterface::Paused
@ Paused
Definition: InterfaceUnit.h:872
TTrainController::SaveSessionTrains
void SaveSessionTrains(int Caller, std::ofstream &SessionFile)
save trains to a session file
Definition: TrainUnit.cpp:13878
TInterface::SpeedButton41
TSpeedButton * SpeedButton41
Definition: InterfaceUnit.h:544
TInterface::TrackInfoMenuItem
TMenuItem * TrackInfoMenuItem
Definition: InterfaceUnit.h:443
TRailGraphics::SpeedBut73NormBlackGlyph
Graphics::TBitmap * SpeedBut73NormBlackGlyph
Definition: GraphicUnit.h:1042
TInterface::Operating
@ Operating
Definition: InterfaceUnit.h:872
TTextHandler
A single object that handles text management.
Definition: TextUnit.h:62
TInterface::EditTimetableMenuItemClick
void __fastcall EditTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3077
TInterface::TakeSignallerControlMenuItemClick
void __fastcall TakeSignallerControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9563
TInterface::TimetableMode
@ TimetableMode
Definition: InterfaceUnit.h:850
TInterface::ScreenUpButtonClick
void __fastcall ScreenUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8393
TInterface::ShowHideTTButtonClick
void __fastcall ShowHideTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3248
TInterface::ImageMenu
TMenuItem * ImageMenu
Definition: InterfaceUnit.h:449
TInterface::LoadGroundSignalGlyphs
void LoadGroundSignalGlyphs(int Caller)
In trackbuild display ground signal types on signal buttons.
Definition: InterfaceUnit.cpp:18286
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:164
TInterface::CPArrivalsCheckBox
TCheckBox * CPArrivalsCheckBox
Definition: InterfaceUnit.h:241
TInterface::OneEntryTimetableMemo
TMemo * OneEntryTimetableMemo
the single service editing and display area on the right hand side of the timetable edit screen
Definition: InterfaceUnit.h:396
TInterface::SelectBitmapVLoc
int SelectBitmapVLoc
the original (prior to moving & after finished moving) VLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1069
TInterface::LengthOKButtonClick
void __fastcall LengthOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1283
TInterface::SpeedButton47
TSpeedButton * SpeedButton47
Definition: InterfaceUnit.h:550
TInterface::OutputLog1MouseDown
void __fastcall OutputLog1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10841
NotStarted
@ NotStarted
Definition: TrainUnit.h:80
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4149
TInterface::AppDeactivate
void __fastcall AppDeactivate(TObject *Sender)
Definition: InterfaceUnit.cpp:734
TInterface::UnrestrictedButtonClick
void __fastcall UnrestrictedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2048
TInterface::ExportTTMenuItem
TMenuItem * ExportTTMenuItem
Definition: InterfaceUnit.h:414
TInterface::SaveTTKeyFlag
bool SaveTTKeyFlag
Definition: InterfaceUnit.h:1015
TRailGraphics::SpeedBut71NormBlackGlyph
Graphics::TBitmap * SpeedBut71NormBlackGlyph
Definition: GraphicUnit.h:1040
TInterface::SelectNewGraphicClick
void __fastcall SelectNewGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12135
TInterface::SpeedButtonClick
void __fastcall SpeedButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:859
TTrack::GetHLocMax
int GetHLocMax()
Definition: TrackUnit.h:766
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3144
TInterface::CPEditArrRange
TEdit * CPEditArrRange
Definition: InterfaceUnit.h:244
TInterface::ErrorButtonClick
void __fastcall ErrorButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10257
TTrainController::SPADEvents
int SPADEvents
Definition: TrainUnit.h:766
TInterface::PasteTTEntryButton
TButton * PasteTTEntryButton
Definition: InterfaceUnit.h:131
TInterface::SpeedButton139
TSpeedButton * SpeedButton139
Definition: InterfaceUnit.h:642
TInterface::SpeedButton3
TSpeedButton * SpeedButton3
Definition: InterfaceUnit.h:506
TTrain::ZeroPowerNoRepeatShuttleMessage
bool ZeroPowerNoRepeatShuttleMessage
Definition: TrainUnit.h:307
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TInterface::SetLevel2PrefDirMode
void SetLevel2PrefDirMode(int Caller)
Sets the Level2PrefDirMode user mode, using the Level2PrefDirMode variable to determine the mode.
Definition: InterfaceUnit.cpp:13815
TInterface::SetGapsButton
TBitBtn * SetGapsButton
Definition: InterfaceUnit.h:63
TTrain::ActionVectorEntryPtr
TActionVectorEntry * ActionVectorEntryPtr
points to the current position in the ActionVector (a member of the TTrainDataEntry class)
Definition: TrainUnit.h:335
TTrainDataEntry
Contains all data for a single train.
Definition: TrainUnit.h:177
clSignalStopBackground
#define clSignalStopBackground
Definition: GraphicUnit.h:299
TTrainController::LateDeps
int LateDeps
Definition: TrainUnit.h:759
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:16926
TInterface::ExitMenuItemClick
void __fastcall ExitMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5286
TrackUnit.h
TInterface::SpeedButton29
TSpeedButton * SpeedButton29
Definition: InterfaceUnit.h:532
TInterface::SpeedButton35
TSpeedButton * SpeedButton35
Definition: InterfaceUnit.h:538
TInterface::ScreenDownButtonClick
void __fastcall ScreenDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8333
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:17117
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:8107
TDisplay::ClearDisplay
void ClearDisplay(int Caller)
Empty the display.
Definition: DisplayUnit.cpp:181
TDisplay::Top
int Top()
Return the top pixel position of the screen.
Definition: DisplayUnit.h:120
TInterface::ExitPrefDirButtonClick
void __fastcall ExitPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1917
TInterface::SaveErrorFile
void SaveErrorFile()
Save the error log after an error has been thrown - no need for a caller.
Definition: InterfaceUnit.cpp:17532
TTrain::SendMissedActionLogs
void SendMissedActionLogs(int Caller, int IncNum, TActionVectorEntry *Ptr)
Missed actions (see NameInTimetableBeforeCDT above) sent to the performance log and performance file.
Definition: TrainUnit.cpp:5811
TInterface::SpeedVariableLabel2
TLabel * SpeedVariableLabel2
Definition: InterfaceUnit.h:112
TInterface::TrainInfoMenuItem
TMenuItem * TrainInfoMenuItem
Definition: InterfaceUnit.h:445
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1396
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1482
TInterface::TrainStatusInfoOnOffMenuItemClick
void __fastcall TrainStatusInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5350
TInterface::ConverttoRightHandSignalsMenuItem
TMenuItem * ConverttoRightHandSignalsMenuItem
Definition: InterfaceUnit.h:467
TInterface::SpeedButton96
TSpeedButton * SpeedButton96
Definition: InterfaceUnit.h:599
TInterface::TTClockxHalfButtonClick
void __fastcall TTClockxHalfButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11610
TInterface::OutputLog3
TLabel * OutputLog3
Definition: InterfaceUnit.h:293
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
TOnePrefDir::ExternalStorePrefDirElement
void ExternalStorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map - used by other classes.
Definition: TrackUnit.h:1311
clB5G5R4
#define clB5G5R4
Definition: GraphicUnit.h:285
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:658
TInterface::SaveImageNoGridMenuItemClick
void __fastcall SaveImageNoGridMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2425
TInterface::SpeedButton25
TSpeedButton * SpeedButton25
Definition: InterfaceUnit.h:528
TInterface::HelpMenu
TMenuItem * HelpMenu
Definition: InterfaceUnit.h:455
TInterface::TrackOKButtonClick
void __fastcall TrackOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:884
TTrainController::CheckSessionLockedRoutes
bool CheckSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for locked routes, true for success.
Definition: TrainUnit.cpp:13982
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:2872
TInterface::GapsSetImage
TImage * GapsSetImage
Definition: InterfaceUnit.h:275
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TInterface::LocationNameComboBoxKeyUp
void __fastcall LocationNameComboBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4558
TTrainController::CreateTTAnalysisFile
bool CreateTTAnalysisFile(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir, bool ArrChecked, bool DepChecked, bool AtLocChecked, int ArrRange, int DepRange)
Generate a timetable analysis file in the 'Formatted Timetables' folder, return false if failed for a...
Definition: TrainUnit.cpp:14824
TInterface::RevertToOriginalRouteSelector
void RevertToOriginalRouteSelector(int Caller)
Clears any route start markers, enables or disables the route cancel button, and resets the informati...
Definition: InterfaceUnit.cpp:12728
TInterface::FileIntegrityCheck
bool FileIntegrityCheck(int Caller, char *FileName) const
Check integrity of a railway file prior to loading, return true for success.
Definition: InterfaceUnit.cpp:12575
TInterface::TTLastServicePtr
TTEVPtr TTLastServicePtr
timetable entry value pointers used during timetable editing
Definition: InterfaceUnit.h:1132
TTrainController::CheckSessionTrains
bool CheckSessionTrains(int Caller, std::ifstream &InFile)
Part of the session file integrity check for train entries, true for success.
Definition: TrainUnit.cpp:13920
TInterface::SpeedButton126
TSpeedButton * SpeedButton126
Definition: InterfaceUnit.h:629
TakeSignallerControl
@ TakeSignallerControl
Definition: TrainUnit.h:49
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:11111
Simple
@ Simple
Definition: TrackUnit.h:63
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:689
TTrain::ZeroPowerNoRepeatShuttleOrNewServiceMessage
bool ZeroPowerNoRepeatShuttleOrNewServiceMessage
flags to indicate whether the respective message has been sent
Definition: TrainUnit.h:308
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TInterface::SetInitialTrackModeEditMenu
void SetInitialTrackModeEditMenu()
Enables or disables the initial Edit mode submenu items in Track mode.
Definition: InterfaceUnit.cpp:18059
TInterface::DeleteMenuItem
TMenuItem * DeleteMenuItem
Definition: InterfaceUnit.h:437
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2496
TInterface::TTClockAdjustOKButtonClick
void __fastcall TTClockAdjustOKButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12152
TInterface::ChangeDirectionMenuItemClick
void __fastcall ChangeDirectionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9754
TInterface::PointsFlashDuration
float PointsFlashDuration
duration of the flash period when changing points manually
Definition: InterfaceUnit.h:1026
TInterface::LocationNameComboBoxClick
void __fastcall LocationNameComboBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4487
TInterface::TTServiceSyntaxCheckKeyFlag
bool TTServiceSyntaxCheckKeyFlag
Definition: InterfaceUnit.h:1013
TInterface::TLevel2OperMode
TLevel2OperMode
Definition: InterfaceUnit.h:871
TInterface::ConsecSignalsRoute
bool ConsecSignalsRoute
true when AutoSig or preferred route building selected during operation (always same state as Preferr...
Definition: InterfaceUnit.h:928
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:11339
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5180
TTrain::BackgroundColour
TColor BackgroundColour
the background colour of the train's headcode graphics
Definition: TrainUnit.h:450
TInterface::LengthCancelButtonClick
void __fastcall LengthCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1465
TTrain
Definition: TrainUnit.h:271
TInterface::OutputLog5
TLabel * OutputLog5
Definition: InterfaceUnit.h:295
TTrainController::CheckTimeValidity
bool CheckTimeValidity(int Caller, AnsiString TimeStr, TDateTime &Time)
returns true if the time complies with requirements
Definition: TrainUnit.cpp:9629
clSignallerStopped
#define clSignallerStopped
Definition: GraphicUnit.h:298
TTextHandler::SelectTextVector
TTextVector SelectTextVector
Definition: TextUnit.h:69
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:151
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:9807
TInterface::CallOnImage
TImage * CallOnImage
Definition: InterfaceUnit.h:261
TInterface::PerformancePanelDragStartY
int PerformancePanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1060
TInterface::LocationNameTextBox
TEdit * LocationNameTextBox
edit box that accepts location names
Definition: InterfaceUnit.h:93
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:542
TInterface::SaveSessionFlag
bool SaveSessionFlag
true when a session save command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:958
TTrainController::ContinuationTrainExpectationMultiMap
TContinuationTrainExpectationMultiMap ContinuationTrainExpectationMultiMap
Multimap for TContinuationTrainExpectationEntry objects, the access key is the expectation time.
Definition: TrainUnit.h:789
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:6485
TInterface::SpeedButton73
TSpeedButton * SpeedButton73
Definition: InterfaceUnit.h:576
TInterface::TTLabel4
TLabel * TTLabel4
Definition: InterfaceUnit.h:341
TTrain::StoppedForTrainInFront
bool StoppedForTrainInFront
Definition: TrainUnit.h:427
TInterface::ConflictAnalysisKeyFlag
bool ConflictAnalysisKeyFlag
Definition: InterfaceUnit.h:1019
GapJump
@ GapJump
Definition: TrackUnit.h:63
TInterface::Level2OperMode
enum TInterface::TLevel2OperMode Level2OperMode
TInterface::SigsOnRightImage1
TImage * SigsOnRightImage1
Definition: InterfaceUnit.h:281
TInterface::SaveRailwayPDPButton
TBitBtn * SaveRailwayPDPButton
Save button on PrefDirPanel.
Definition: InterfaceUnit.h:118
TInterface::SpeedButton62
TSpeedButton * SpeedButton62
Definition: InterfaceUnit.h:565
TInterface::SpeedButton58
TSpeedButton * SpeedButton58
Definition: InterfaceUnit.h:561
TTrainController::MissedStops
int MissedStops
Definition: TrainUnit.h:761
TInterface::TempTTFileName
AnsiString TempTTFileName
the name for the temporary file used to save loaded timetables for storage in session files & error l...
Definition: InterfaceUnit.h:917
TInterface::PrefDirMode
@ PrefDirMode
Definition: InterfaceUnit.h:850
TInterface::PassRedSignalMenuItem
TMenuItem * PassRedSignalMenuItem
Definition: InterfaceUnit.h:463
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:147
TRailGraphics::bmGreenRect
Graphics::TBitmap * bmGreenRect
Definition: GraphicUnit.h:520
TInterface::TTClockExitButtonClick
void __fastcall TTClockExitButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11473
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:147
TTrack::Raising
@ Raising
Definition: TrackUnit.h:523
TTrainController::FinishedOperation
void FinishedOperation(int Caller)
called when exiting operation mode to delete all trains and timetable data etc
Definition: TrainUnit.cpp:8120
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:557
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:8834
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TTrain::MidElement
int MidElement
Definition: TrainUnit.h:327
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool ConsecSignalsRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:15473
TInterface::SpeedButton5
TSpeedButton * SpeedButton5
Definition: InterfaceUnit.h:508
TInterface::LocationNameKeyUp
void __fastcall LocationNameKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:1076
TInterface::LoadUserGraphicDialog
TOpenDialog * LoadUserGraphicDialog
Definition: InterfaceUnit.h:490
TAllRoutes::CallonVector
std::vector< TCallonEntry > CallonVector
the store of all call-on entries
Definition: TrackUnit.h:1541
TInterface::OutputLog8MouseDown
void __fastcall OutputLog8MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10909
TInterface::SetPausedOrZoomedInfoCaption
void SetPausedOrZoomedInfoCaption(int Caller)
Sets the information panel message for zoom-out or paused modes.
Definition: InterfaceUnit.cpp:17501
TTrain::LeadElement
int LeadElement
Definition: TrainUnit.h:327
TInterface::CurDir
AnsiString CurDir
the full path to the folder where railway.exe resides
Definition: InterfaceUnit.h:903
TInterface::OneEntryTimetableMemoKeyUp
void __fastcall OneEntryTimetableMemoKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4515
TInterface::RouteCancelButton
TBitBtn * RouteCancelButton
Definition: InterfaceUnit.h:197
TInterface::SpeedButton26
TSpeedButton * SpeedButton26
Definition: InterfaceUnit.h:529
TInterface::HomeButton
TBitBtn * HomeButton
Definition: InterfaceUnit.h:252
TRailGraphics
Handles graphic data & functions, single object defined.
Definition: GraphicUnit.h:308
TInterface::OperatorActionPanelDragStartY
int OperatorActionPanelDragStartY
as above for 'Y'
Definition: InterfaceUnit.h:1053
TTrain::RepeatNumber
int RepeatNumber
indicates which of the repeating services this train represents (0 = first service)
Definition: TrainUnit.h:321
TTrainDataEntry::ActionVector
TActionVector ActionVector
all the actions for the train
Definition: TrainUnit.h:195
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:633
TInterface::NewHomeButton
TBitBtn * NewHomeButton
Definition: InterfaceUnit.h:253
TInterface::ResetAll
void ResetAll(int Caller)
Called during ClearEverything and on startup to reset all major railway data values.
Definition: InterfaceUnit.cpp:15443
TInterface::SpeedButton75
TSpeedButton * SpeedButton75
Definition: InterfaceUnit.h:578
TTrainController::LoadSessionLockedRoutes
void LoadSessionLockedRoutes(int Caller, std::ifstream &SessionFile)
load locked routes from a session file
Definition: TrainUnit.cpp:13961
TInterface::DistancesMarked
bool DistancesMarked
true when setting lengths, used to ensure the screen distance markers are redisplayed when the screen...
Definition: InterfaceUnit.h:936
TTrainController::EarlyPasses
int EarlyPasses
Definition: TrainUnit.h:756
TTrain::HeadCode
AnsiString HeadCode
needs own HeadCode because repeat entries will differ from TrainDataEntry.HeadCode
Definition: TrainUnit.h:290
TInterface::TrackBuildPanel
TPanel * TrackBuildPanel
'Build/modify railway' panel
Definition: InterfaceUnit.h:356
TTrain::EntryTime
TDateTime EntryTime
Definition: TrainUnit.h:409
TInterface::CutMoving
@ CutMoving
Definition: InterfaceUnit.h:881
TInterface::SpeedButton134
TSpeedButton * SpeedButton134
Definition: InterfaceUnit.h:637
TInterface::SelectLengthsMenuItem
TMenuItem * SelectLengthsMenuItem
Definition: InterfaceUnit.h:438
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1262
TInterface::SpeedButton72
TSpeedButton * SpeedButton72
Definition: InterfaceUnit.h:575
TInterface::ValidateTimetableButton
TButton * ValidateTimetableButton
Definition: InterfaceUnit.h:143
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5411
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1402
InterfaceUnit.h
TInterface::CopyMenuItemClick
void __fastcall CopyMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8767
TInterface::PerformanceLogButton
TBitBtn * PerformanceLogButton
Definition: InterfaceUnit.h:199
TInterface::FORMATTEDTT_DIR_NAME
static const UnicodeString FORMATTEDTT_DIR_NAME
Definition: InterfaceUnit.h:866
TInterface::HighLightOneGap
bool HighLightOneGap(int Caller, int &HLoc, int &VLoc)
Called during gap setting to mark a gap with a red ellipse and ask user to select the corresponding g...
Definition: InterfaceUnit.cpp:12497
TTrain::OneLengthAccelDecel
bool OneLengthAccelDecel
set when a train can only move forwards one element before stopping but needs to accelerate for the f...
Definition: TrainUnit.h:357
TTrain::FloatingLabelNextString
AnsiString FloatingLabelNextString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the 'Next' action.
Definition: TrainUnit.cpp:6336
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers
Definition: TrackUnit.h:534
TTrain::FailedTrainNoFinishJoinMessage
bool FailedTrainNoFinishJoinMessage
Definition: TrainUnit.h:302
TInterface::SpeedButton55
TSpeedButton * SpeedButton55
Definition: InterfaceUnit.h:558
TInterface::OperatorActionPanel
TPanel * OperatorActionPanel
new v2.2.0 panel housing the OAListBox with list of trains and times to act
Definition: InterfaceUnit.h:384
TInterface::NextTTEntryButton
TButton * NextTTEntryButton
Definition: InterfaceUnit.h:128
TTextHandler::SelectTextVectorSize
unsigned int SelectTextVectorSize(int Caller)
return the number of items in SelectTextVector
Definition: TextUnit.cpp:516
TInterface::TrackTrainFloat
void TrackTrainFloat(int Caller)
Controls the floating window function, called during the ClockTimer2 function.
Definition: InterfaceUnit.cpp:14143
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:138
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TInterface::AddLocationNameText
void AddLocationNameText(int Caller, AnsiString Name, int HPos, int VPos, bool UseEnteredPosition)
Add 'Name' to TextVector and display on screen at a position determined by the shape and size of the ...
Definition: InterfaceUnit.cpp:18165
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackElement.at(At)
Definition: TrackUnit.cpp:8940
TTextHandler::CheckTextElementsInFile
bool CheckTextElementsInFile(int Caller, std::ifstream &VecFile)
check the validity of text items in VecFile prior to loading, return true for success
Definition: TextUnit.cpp:349
TInterface::ConverttoRightHandSignalsMenuItemClick
void __fastcall ConverttoRightHandSignalsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11920
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:295
TTrack::GetVLocMax
int GetVLocMax()
Definition: TrackUnit.h:776
TTrainController::LoadSessionContinuationAutoSigEntries
void LoadSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
load ContinuationAutoSigEntries from a session file
Definition: TrainUnit.cpp:14044
TInterface::HighlightOneEntryInAllEntriesTTListBox
void HighlightOneEntryInAllEntriesTTListBox(int Caller, int Position)
Called during timetable editing to highlight in red a single entry in the list of all entries in the ...
Definition: InterfaceUnit.cpp:5220
TInterface::DistanceStart
@ DistanceStart
Definition: InterfaceUnit.h:880
TInterface::ErrorMessage
TMemo * ErrorMessage
the text of the normal error message screen
Definition: InterfaceUnit.h:392
TInterface::ExitPrefDirButton
TBitBtn * ExitPrefDirButton
Definition: InterfaceUnit.h:120
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:697
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:123
TInterface::TrackLengthPanel
TPanel * TrackLengthPanel
the panel that contains the distance/speed setting buttons and edit boxes
Definition: InterfaceUnit.h:377
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:520
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3408
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:981
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:982
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:753
TTrainController::OtherMissedEvents
int OtherMissedEvents
Definition: TrainUnit.h:765
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:425
TInterface::MoveTextOrGraphicButton
TBitBtn * MoveTextOrGraphicButton
Definition: InterfaceUnit.h:66
TTrainDataEntry::Description
AnsiString Description
headcode is the first train's headcode, rest are calculated from repeat information; ServiceReference...
Definition: TrainUnit.h:179
TInterface::RouteContinuing
@ RouteContinuing
Definition: InterfaceUnit.h:885
TTrain::ExitSpeedHalf
double ExitSpeedHalf
speed when half way into the next element
Definition: TrainUnit.h:377
SignalPost
@ SignalPost
Definition: TrackUnit.h:63
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:8072
TTrain::LastActionTime
TDateTime LastActionTime
time of the last timetabled action, used to ensure at least a 30 second delay before the next action
Definition: TrainUnit.h:413
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:15627
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:421
TInterface::InfoPanel
TPanel * InfoPanel
the general information panel (with blue 'i' symbol)
Definition: InterfaceUnit.h:371
TInterface::TextOrUserGraphicGridButtonClick
void __fastcall TextOrUserGraphicGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1683
TInterface::FormKeyDown
void __fastcall FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:10357
TInterface::MoveTTEntryDownButton
TButton * MoveTTEntryDownButton
Definition: InterfaceUnit.h:134
TInterface::CheckTimetableFromSessionFile
bool CheckTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Check the timetable file embedded within a session file & return false for error, called during Sessi...
Definition: InterfaceUnit.cpp:16613
TRailGraphics::SpeedBut71GrndBlackGlyph
Graphics::TBitmap * SpeedBut71GrndBlackGlyph
Definition: GraphicUnit.h:1048
TInterface::DeleteTTEntryButtonClick
void __fastcall DeleteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3701
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:6499
TInterface::WarningFlashCount
int WarningFlashCount
increments each clock cycle to a max. of 4 then resets to 0, used to toggle bool WarningFlash - see a...
Definition: InterfaceUnit.h:1095
TInterface::StartWholeRailwayMoveHPos
int StartWholeRailwayMoveHPos
mouse X position when start to move the whole railway
Definition: InterfaceUnit.h:1073
TInterface::SpeedButton93
TSpeedButton * SpeedButton93
Definition: InterfaceUnit.h:596
TInterface::SpeedButton119
TSpeedButton * SpeedButton119
Definition: InterfaceUnit.h:622
TInterface::SelectedGraphicFileName
AnsiString SelectedGraphicFileName
filename for selected graphic set during LoadGraphic
Definition: InterfaceUnit.h:921
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:7450
TInterface::TrackBuildPanelLabel
TLabel * TrackBuildPanelLabel
label to the left of TrackBuildPanel
Definition: InterfaceUnit.h:314
clNormalBackground
#define clNormalBackground
Definition: GraphicUnit.h:297
TInterface::TTClockAdjButtonClick
void __fastcall TTClockAdjButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11442
TInterface::RAILWAY_DIR_NAME
static const UnicodeString RAILWAY_DIR_NAME
Definition: InterfaceUnit.h:861
TTrainController::SecondPassActions
bool SecondPassActions(int Caller, bool GiveMessages)
Carry out further detailed timetable consistency checks, return true for success.
Definition: TrainUnit.cpp:10667
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:15612
TInterface::SPADImage
TImage * SPADImage
Definition: InterfaceUnit.h:265
TInterface::AddTrackButton
TBitBtn * AddTrackButton
Definition: InterfaceUnit.h:62
TInterface::MainMenu1
TMainMenu * MainMenu1
the program menu
Definition: InterfaceUnit.h:389
TInterface::OutputLog7MouseDown
void __fastcall OutputLog7MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10899
Concourse
@ Concourse
Definition: TrackUnit.h:64
TTextHandler::TTextVectorIterator
std::vector< TTextItem >::iterator TTextVectorIterator
Definition: TextUnit.h:66
TTrainController::SPADRisks
int SPADRisks
Definition: TrainUnit.h:767
TInterface::LocationNamesNotSetImage
TImage * LocationNamesNotSetImage
Definition: InterfaceUnit.h:278
TInterface::FloatingPanel
TPanel * FloatingPanel
new for v2.2.0 where label sits in it and it autosizes to the label. Labels are not TWinControls so t...
Definition: InterfaceUnit.h:381
TRailGraphics::SpeedBut68NormBlackGlyph
Graphics::TBitmap * SpeedBut68NormBlackGlyph
Definition: GraphicUnit.h:1037
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:706
TInterface::SaveMenuItemClick
void __fastcall SaveMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2357
TInterface::ScreenGridButtonClick
void __fastcall ScreenGridButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1787
TTrain::EntrySpeed
double EntrySpeed
speed at which the train enters the next element
Definition: TrainUnit.h:375
TInterface::UserGraphicMoveHPos
int UserGraphicMoveHPos
Definition: InterfaceUnit.h:1093
TInterface::PassRedSignalMenuItemClick
void __fastcall PassRedSignalMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10026
TInterface::ReselectMenuItem
TMenuItem * ReselectMenuItem
Definition: InterfaceUnit.h:430
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:11795
TInterface::ClearEverything
bool ClearEverything(int Caller)
First check whether a railway file has changed and if so ask user if really wants to close it without...
Definition: InterfaceUnit.cpp:12525
TInterface::PrefDirContinuing
@ PrefDirContinuing
Definition: InterfaceUnit.h:876
TTrain::TrainGone
bool TrainGone
set when train has left the railway, so it can be removed from the display at the next clock tick
Definition: TrainUnit.h:423
TRailGraphics::SpeedBut70NormBlackGlyph
Graphics::TBitmap * SpeedBut70NormBlackGlyph
Definition: GraphicUnit.h:1039
TTrainController::OnTimePasses
int OnTimePasses
Definition: TrainUnit.h:764
TInterface::SaveAsMenuItem
TMenuItem * SaveAsMenuItem
Definition: InterfaceUnit.h:410
TInterface::MoveTextOrGraphicButtonClick
void __fastcall MoveTextOrGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:998
TTrainController::SigSHigh
bool SigSHigh
Definition: TrainUnit.h:733
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4074
TInterface::ZoomButton
TBitBtn * ZoomButton
Definition: InterfaceUnit.h:254
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1597
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:94
TInterface::CopyTTEntryButton
TButton * CopyTTEntryButton
Definition: InterfaceUnit.h:129
TInterface::ErrorMessageStoreImage
TMemo * ErrorMessageStoreImage
the text of the error message for failure to draw trains in SaveOperatingImage
Definition: InterfaceUnit.h:394
TInterface::SpeedButton76
TSpeedButton * SpeedButton76
Definition: InterfaceUnit.h:579
TTrain::StoppedAfterSPAD
bool StoppedAfterSPAD
Definition: TrainUnit.h:427
TInterface::SpeedButton145
TSpeedButton * SpeedButton145
Definition: InterfaceUnit.h:648
TInterface::NoPrefDirMode
@ NoPrefDirMode
Definition: InterfaceUnit.h:876
TInterface::SpeedButton88
TSpeedButton * SpeedButton88
Definition: InterfaceUnit.h:591
TTrainController::OnTimeArrivals
int OnTimeArrivals
Definition: TrainUnit.h:762
TInterface::MoveTTEntryDownButtonClick
void __fastcall MoveTTEntryDownButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4201
TInterface::PerformanceLogBox
TMemo * PerformanceLogBox
the performance log displayed during operation
Definition: InterfaceUnit.h:398
TRailGraphics::SpeedBut72GrndBlackGlyph
Graphics::TBitmap * SpeedBut72GrndBlackGlyph
Definition: GraphicUnit.h:1049
TInterface::SpeedButton28
TSpeedButton * SpeedButton28
Definition: InterfaceUnit.h:531
TAllRoutes::LevelCrossingBarrierUpDelay
const float LevelCrossingBarrierUpDelay
the full value in seconds for which the level crossing flashes prior to closing to trains
Definition: TrackUnit.h:1561
TInterface::SpeedTopLabel
TLabel * SpeedTopLabel
Definition: InterfaceUnit.h:179
TInterface::OperateButton
TBitBtn * OperateButton
Definition: InterfaceUnit.h:193
clFrontCodeSignaller
#define clFrontCodeSignaller
Definition: GraphicUnit.h:295
TInterface::SignallerJoinedByMenuItemClick
void __fastcall SignallerJoinedByMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9847
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:671
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TActionVectorEntry::ArrivalTime
TDateTime ArrivalTime
Definition: TrainUnit.h:106
TTrain::StoppedAtBuffers
bool StoppedAtBuffers
Definition: TrainUnit.h:427
TInterface::SkipFormResizeEvent
bool SkipFormResizeEvent
added at v2.1.0 to avoid calling the event during startup and shutdown
Definition: InterfaceUnit.h:972
TTrackElement::TempMarker
bool TempMarker
Utility marker for program use.
Definition: TrackUnit.h:135
TTrain::Mass
int Mass
in kg
Definition: TrainUnit.h:405
TInterface::TrackInfoOnOffMenuItem
TMenuItem * TrackInfoOnOffMenuItem
Definition: InterfaceUnit.h:444
TDisplay::ShowWarningLog
void ShowWarningLog(int Caller)
Show the warnings after timetable clock adjusted.
Definition: DisplayUnit.cpp:493
TInterface::SpeedButton121
TSpeedButton * SpeedButton121
Definition: InterfaceUnit.h:624
TTrainController::ProcessOneTimetableLine
bool ProcessOneTimetableLine(int Caller, int Count, AnsiString OneLine, bool &EndOfFile, bool FinalCall, bool GiveMessages, bool CheckLocationsExistInRailway)
Carry out preliminary (mainly syntax) validity checks on a single timetable service entry and (if Fin...
Definition: TrainUnit.cpp:8979
TInterface::SaveAsMenuItemClick
void __fastcall SaveAsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2408
TTextItem
A single piece of text that can be displayed on the railway.
Definition: TextUnit.h:36
TInterface::SpeedButton136
TSpeedButton * SpeedButton136
Definition: InterfaceUnit.h:639
TInterface::PointFlash
TGraphicElement * PointFlash
Definition: InterfaceUnit.h:1109
TInterface::TrackLinkedImage
TImage * TrackLinkedImage
Definition: InterfaceUnit.h:273
TTrain::LeadExitPos
int LeadExitPos
Definition: TrainUnit.h:327
TInterface::SelectPickedUp
bool SelectPickedUp
true when a valid selected screen area has been clicked after a 'Copy' or 'Cut' selected in the 'Edit...
Definition: InterfaceUnit.h:966
TDisplay::ResetZoomOutOffsets
void ResetZoomOutOffsets()
Reset the zoomed-out screen display to the 'Home' position.
Definition: DisplayUnit.h:208
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:156
TInterface::DevelopmentPanel
TPanel * DevelopmentPanel
used for diagnostic purposes, made visible by ctrl+ alt+ 3
Definition: InterfaceUnit.h:379
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1616
TInterface::PerformancePanel
TPanel * PerformancePanel
displays the operating performance log
Definition: InterfaceUnit.h:373
TTrainController::DerailWarning
bool DerailWarning
Definition: TrainUnit.h:722
TInterface::CopyMoving
@ CopyMoving
Definition: InterfaceUnit.h:881
TInterface::TimetableEditPanel
TPanel * TimetableEditPanel
the large panel that contains all the main timetable components
Definition: InterfaceUnit.h:365
TInterface::RouteMode
enum TInterface::@0 RouteMode
route building modes
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TInterface::TrainStatusInfoOnOffMenuItem
TMenuItem * TrainStatusInfoOnOffMenuItem
Definition: InterfaceUnit.h:446
TInterface::SetLengthsButtonClick
void __fastcall SetLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1262
TInterface::SaveTTEntryButton
TButton * SaveTTEntryButton
Definition: InterfaceUnit.h:135
TInterface::SpeedButton37
TSpeedButton * SpeedButton37
Definition: InterfaceUnit.h:540
TInterface::BaseMode
@ BaseMode
Definition: InterfaceUnit.h:850
TInterface::SpeedEditBoxKeyUp
void __fastcall SpeedEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11137
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
Definition: TrackUnit.cpp:9620
TInterface::MirrorMenuItem
TMenuItem * MirrorMenuItem
Definition: InterfaceUnit.h:434
TInterface::EveryPrefDir
TOnePrefDir * EveryPrefDir
all the Pref Dir elements in the railway
Definition: InterfaceUnit.h:1120
TTrainController::TotLateDepMins
float TotLateDepMins
Definition: TrainUnit.h:749
TDisplay::ZoomOutFlag
bool ZoomOutFlag
true when zoomed-out
Definition: DisplayUnit.h:69
TInterface::OutputLog8
TLabel * OutputLog8
Definition: InterfaceUnit.h:298
TInterface::SpeedButton1
TSpeedButton * SpeedButton1
See Speedbutton1 detail for track element allocations.
Definition: InterfaceUnit.h:504
TTrainController::TrainVector
TTrainVector TrainVector
vector containing all trains currently in the railway
Definition: TrainUnit.h:797
TInterface::SaveAsSubroutine
void SaveAsSubroutine(int Caller)
Used to save a railway when not already saved - e.g. when not already named or when the 'Save as' men...
Definition: InterfaceUnit.cpp:17964
TInterface::MainScreenMouseDown2
void MainScreenMouseDown2(int Caller, TMouseButton Button, TShiftState Shift, int X, int Y)
Called when mouse button clicked in zoom-in mode.
Definition: InterfaceUnit.cpp:5527
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1408
TInterface::RepairFailedTrainMenuItemClick
void __fastcall RepairFailedTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9936
TInterface::AddLocationName
@ AddLocationName
Definition: InterfaceUnit.h:880
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:7398
TTrack::IsTrackFinished
bool IsTrackFinished()
Indicates whether or not the track has been successfully linked together.
Definition: TrackUnit.h:728
TAllRoutes::AllRoutesClear
void AllRoutesClear()
Erases all routes from AllRoutesVector and from Route2MultiMap.
Definition: TrackUnit.h:1589
TRailGraphics::SpeedBut74GrndBlackGlyph
Graphics::TBitmap * SpeedBut74GrndBlackGlyph
Definition: GraphicUnit.h:1051
TAllRoutes::PointsDelay
const float PointsDelay
the value in seconds for which points flash prior to being changed. Used for the points flash period ...
Definition: TrackUnit.h:1565
TInterface::SaveSession
void SaveSession(int Caller)
Save a session file - see LoadSession for details of additions to the session file.
Definition: InterfaceUnit.cpp:15651
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TAllRoutes::SignalsDelay
const float SignalsDelay
the value in seconds for which signals flash prior to being changed. Used for the route flash period ...
Definition: TrackUnit.h:1567
TDisplay::GetFont
TFont * GetFont()
Return the current screen font.
Definition: DisplayUnit.h:132
TInterface::SpeedButton10
TSpeedButton * SpeedButton10
Definition: InterfaceUnit.h:513
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:284
TInterface::SpeedButton103
TSpeedButton * SpeedButton103
Definition: InterfaceUnit.h:606
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:753
TTrainController::TotEarlyArrMins
float TotEarlyArrMins
values for performance file summary
Definition: TrainUnit.h:745
TInterface::PerformancePanelStartDrag
void __fastcall PerformancePanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5455
TInterface::TempCursorSet
bool TempCursorSet
indicates that a screen cursor has been stored in TempCursor for redisplay after a temporary cursor (...
Definition: InterfaceUnit.h:974
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:10598
TInterface::SpeedButton85
TSpeedButton * SpeedButton85
Definition: InterfaceUnit.h:588
TInterface::PasteMenuItemClick
void __fastcall PasteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9353
TInterface::MainScreenMouseUp
void __fastcall MainScreenMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7209
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TInterface::SaveTempTimetableFile
void SaveTempTimetableFile(int Caller, AnsiString InFileName)
Save a timetable as a temporary file either on loading directly or on loading a session file....
Definition: InterfaceUnit.cpp:17725
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1571
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TInterface::RotateMenuItemClick
void __fastcall RotateMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8902
TTrainDataEntry::SignallerSpeed
int SignallerSpeed
in km/h for use when under signaller control
Definition: TrainUnit.h:191
TInterface::OverallDistance
int OverallDistance
Definition: InterfaceUnit.h:1055
TInterface::SpeedButton105
TSpeedButton * SpeedButton105
Definition: InterfaceUnit.h:608
TInterface::SpeedButton83
TSpeedButton * SpeedButton83
Definition: InterfaceUnit.h:586
TTrain::AbleToMove
bool AbleToMove(int Caller)
Indicates that a train is not prevented from moving - used to allow appropriate popup menu options wh...
Definition: TrainUnit.cpp:6236
TTrainController::MTBFHours
double MTBFHours
Mean time between failures in timetable clock hours.
Definition: TrainUnit.h:736
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:11078
TInterface::RestoreAllDefaultLengthsButtonClick
void __fastcall RestoreAllDefaultLengthsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1593
TInterface::SpeedButton131
TSpeedButton * SpeedButton131
Definition: InterfaceUnit.h:634
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignalsRoute, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:12617
TInterface::FlipMenuItemClick
void __fastcall FlipMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8786
TInterface::TrainTTInfoOnOffMenuItem
TMenuItem * TrainTTInfoOnOffMenuItem
Definition: InterfaceUnit.h:447
TInterface::AllSetUpFlag
bool AllSetUpFlag
false during initial start up, true when all set up to allow MasterClock to start
Definition: InterfaceUnit.h:924
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3226
TInterface::LocationNameButton
TBitBtn * LocationNameButton
Definition: InterfaceUnit.h:67
TInterface::SpeedButton101
TSpeedButton * SpeedButton101
Definition: InterfaceUnit.h:604
TTrain::TrainMode
TTrainMode TrainMode
mode of operation - either Timetable (running under timetable control) or Signaller (running under si...
Definition: TrainUnit.h:415
TInterface::LoadRailway
void LoadRailway(int Caller, AnsiString LoadFileName)
Load a railway file. The Active elements marker now has a '1' at the end if there are user graphics t...
Definition: InterfaceUnit.cpp:2228
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:9667
TInterface::TextOrUserGraphicGridButton
TBitBtn * TextOrUserGraphicGridButton
Definition: InterfaceUnit.h:69
TInterface::PointFlashVectorPosition
int PointFlashVectorPosition
Definition: InterfaceUnit.h:1062
TInterface::AddSubMinsBoxKeyUp
void __fastcall AddSubMinsBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:4540
TInterface::ExitOperationButtonClick
void __fastcall ExitOperationButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2137
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1499
TInterface::TTClockAdd1hButtonClick
void __fastcall TTClockAdd1hButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11685
TUtilities::Format96HHMM
AnsiString Format96HHMM(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm where hh runs from 00 to 95 & resets when it...
Definition: Utilities.cpp:535
TInterface::TTClockx2ButtonClick
void __fastcall TTClockx2ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11515
TInterface::PerformancePanelDragStartX
int PerformancePanelDragStartX
mouse 'X' position when the performance panel begins to be dragged
Definition: InterfaceUnit.h:1058
TInterface::SpeedButton45
TSpeedButton * SpeedButton45
Definition: InterfaceUnit.h:548
TInterface::SpeedEditBox2KeyUp
void __fastcall SpeedEditBox2KeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11291
TInterface::SavedFileName
AnsiString SavedFileName
the full path and filename of the loaded railway
Definition: InterfaceUnit.h:915
TInterface::PlanPrefDirsMenuItemClick
void __fastcall PlanPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1814
TInterface::OperatingPanel
TPanel * OperatingPanel
'Operate railway' panel
Definition: InterfaceUnit.h:362
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:814
TInterface::SpeedButton141
TSpeedButton * SpeedButton141
Definition: InterfaceUnit.h:644
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
Plot & open (to trains) all level crossings linked to TrackElement.
Definition: TrackUnit.cpp:5618
TInterface::ShowOperatorActionPanel
bool ShowOperatorActionPanel
true when the 'trains needing action' button has been clicked during operation (new at v2....
Definition: InterfaceUnit.h:988
TTrack::GetGapVLoc
int GetGapVLoc()
Definition: TrackUnit.h:761
TInterface::SpeedButton124
TSpeedButton * SpeedButton124
Definition: InterfaceUnit.h:627
TUtilities::CheckFileString
bool CheckFileString(std::ifstream &InFile)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success
Definition: Utilities.cpp:356
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:10898
TRailGraphics::bmGrid
Graphics::TBitmap * bmGrid
Definition: GraphicUnit.h:521
TInterface::RestoreFocusPanel
TPanel * RestoreFocusPanel
Panel used to restore focus to Interface to enable cursor keys to move screen.
Definition: InterfaceUnit.h:353
TInterface::BlackBgndMenuItem
TMenuItem * BlackBgndMenuItem
Definition: InterfaceUnit.h:425
SignallerControlStop
@ SignallerControlStop
Definition: TrainUnit.h:51
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:706
TInterface::FloatingLabel
TLabel * FloatingLabel
the floating window that displays track & train information
Definition: InterfaceUnit.h:334
TInterface::NewTTEntryButton
TButton * NewTTEntryButton
Definition: InterfaceUnit.h:137
TTrainController::ExcessLCDownMins
float ExcessLCDownMins
total excess time in minutes over the 3 minutes barriers down allowance for level crossings
Definition: TrainUnit.h:743
TInterface::SubMinsButtonClick
void __fastcall SubMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3453
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:346
TInterface::TimetableControlMenuItemClick
void __fastcall TimetableControlMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9636
TTrack::TActiveTrackElementNameIterator
TActiveTrackElementNameMap::iterator TActiveTrackElementNameIterator
Definition: TrackUnit.h:616
TInterface::DistanceBox
TEdit * DistanceBox
distance/speed setting edit box that accepts distances
Definition: InterfaceUnit.h:89
TInterface::SpeedButton142
TSpeedButton * SpeedButton142
Definition: InterfaceUnit.h:645
TInterface::PresetAutoSigRoutesButton
TBitBtn * PresetAutoSigRoutesButton
Definition: InterfaceUnit.h:198
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:133
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:117
TInterface::TTLabel12
TLabel * TTLabel12
Definition: InterfaceUnit.h:348
TInterface::TTServiceSyntaxCheckButtonClick
void __fastcall TTServiceSyntaxCheckButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4052
TInterface::SpeedButton57
TSpeedButton * SpeedButton57
Definition: InterfaceUnit.h:560
TInterface::TTClockSpeed
float TTClockSpeed
rate at which the timetable clock runs 1 = normal
Definition: InterfaceUnit.h:1030
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TDisplay::PlotAbsolute
void PlotAbsolute(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Definition: DisplayUnit.cpp:419
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5139
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1533
TInterface::TTClockx4ButtonClick
void __fastcall TTClockx4ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11534
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:11732
TTextHandler::TextFound
bool TextFound(int Caller, int HPosInput, int VPosInput, AnsiString &Text)
look for a text item in the vicinity of HPosInput & VPosInput, return true if found & return the foun...
Definition: TextUnit.cpp:225
TInterface::SaveImageAndPrefDirsMenuItemClick
void __fastcall SaveImageAndPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2614
TInterface::AddMinsButton
TButton * AddMinsButton
Definition: InterfaceUnit.h:140
SignallerStepForward
@ SignallerStepForward
Definition: TrainUnit.h:51
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:771
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:527
TInterface::SpeedButton60
TSpeedButton * SpeedButton60
Definition: InterfaceUnit.h:563
TInterface::TrackInfoOnOffMenuItemClick
void __fastcall TrackInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5327
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3434
TTrainController::OpTimeToActUpdateCounter
unsigned int OpTimeToActUpdateCounter
new v2.2.0, incremented in Interface.cpp, controls updating for OpTimeToActPanel
Definition: TrainUnit.h:781
TTrain::BeingCalledOn
bool BeingCalledOn
in course of being called on to a station
Definition: TrainUnit.h:341
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:217
TInterface::AZOrderButtonClick
void __fastcall AZOrderButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4862
TInterface::HiddenScreen
TImage * HiddenScreen
a hidden copy of the railway display screen used during ClearandRebuildRailway (see below) to avoid f...
Definition: InterfaceUnit.h:1115
TInterface::PerformancePanelLabelStartDrag
void __fastcall PerformancePanelLabelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:10268
TInterface::LoadPerformanceFile
void LoadPerformanceFile(int Caller, std::ifstream &InFile)
Load the performance file part of a sessionfile.
Definition: InterfaceUnit.cpp:17355
TInterface::CPCancelButtonClick
void __fastcall CPCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12190
TInterface::OutputLog4MouseDown
void __fastcall OutputLog4MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10870
TInterface::AddGraphic
@ AddGraphic
Definition: InterfaceUnit.h:880
TInterface::SetLevel1Mode
void SetLevel1Mode(int Caller)
Sets the Level1 user mode, using the Level1Mode variable to determine the mode.
Definition: InterfaceUnit.cpp:12757
TInterface::NewHomeButtonClick
void __fastcall NewHomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8621
TInterface::OutputLog4
TLabel * OutputLog4
Definition: InterfaceUnit.h:294
TInterface::FontDialog
TFontDialog * FontDialog
font change dialog
Definition: InterfaceUnit.h:495
TInterface::TrackSelecting
@ TrackSelecting
Definition: InterfaceUnit.h:881
TTrainController::TotLateArrMins
float TotLateArrMins
Definition: TrainUnit.h:748
TInterface::Level2PrefDirMode
enum TInterface::TLevel2PrefDirMode Level2PrefDirMode
TInterface::OperatingPanelLabel
TLabel * OperatingPanelLabel
displays 'Operation' or 'Disabled' on the operating panel during operation for running or paused
Definition: InterfaceUnit.h:322
TInterface::DivergingPointVectorPosition
int DivergingPointVectorPosition
Definition: InterfaceUnit.h:1062
TInterface::OAListBoxMouseUp
void __fastcall OAListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4635
TTrainController::PlotAllTrainsInZoomOutMode
void PlotAllTrainsInZoomOutMode(int Caller, bool Flash)
Plots all trains on screen in zoomed-out mode, state of 'Flash' determines whether the flashing train...
Definition: TrainUnit.cpp:14197
TInterface::SpeedButton108
TSpeedButton * SpeedButton108
Definition: InterfaceUnit.h:611
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1358
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:7365
TInterface::SavePerformanceFile
void SavePerformanceFile(int Caller, std::ofstream &OutFile)
Save performance file part of a session file.
Definition: InterfaceUnit.cpp:17410
TTextItem::Font
TFont * Font
the text font
Definition: TextUnit.h:52
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1512
TTrain::SignallerStopped
bool SignallerStopped
Definition: TrainUnit.h:427
TDisplay::SetFont
void SetFont(TFont *Font)
Set the screen font to 'Font'.
Definition: DisplayUnit.h:215
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1502
TTrain::TrainDataEntryPtr
TTrainDataEntry * TrainDataEntryPtr
points to the current position in the timetable's TrainDataVector
Definition: TrainUnit.h:333
TInterface::TTLabel13
TLabel * TTLabel13
Definition: InterfaceUnit.h:349
TTrainDataEntry::StartSpeed
int StartSpeed
in km/h
Definition: TrainUnit.h:193
TTrainDataEntry::NumberOfTrains
int NumberOfTrains
number of repeats + 1
Definition: TrainUnit.h:189
TTrainController::Derailments
int Derailments
Definition: TrainUnit.h:754
clStationStopBackground
#define clStationStopBackground
Definition: GraphicUnit.h:301
TInterface::AZOrderButton
TButton * AZOrderButton
Definition: InterfaceUnit.h:139
TInterface::SpeedButton86
TSpeedButton * SpeedButton86
Definition: InterfaceUnit.h:589
TInterface::SpeedButton122
TSpeedButton * SpeedButton122
Definition: InterfaceUnit.h:625
Crossover
@ Crossover
Definition: TrackUnit.h:63
TInterface::SpeedButton104
TSpeedButton * SpeedButton104
Definition: InterfaceUnit.h:607
TInterface::SignallerJoinedByMenuItem
TMenuItem * SignallerJoinedByMenuItem
Definition: InterfaceUnit.h:476
TRailGraphics::SpeedBut69NormBlackGlyph
Graphics::TBitmap * SpeedBut69NormBlackGlyph
Definition: GraphicUnit.h:1038
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:6233
TDisplay::ResetZoomInOffsets
void ResetZoomInOffsets()
Reset the zoomed-in screen display to the 'Home' position.
Definition: DisplayUnit.h:201
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:8426
TInterface::RotRightMenuItem
TMenuItem * RotRightMenuItem
Definition: InterfaceUnit.h:474
AtLocation
@ AtLocation
Definition: TrainUnit.h:67
TInterface::ExportTTButton
TButton * ExportTTButton
Definition: InterfaceUnit.h:147
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
Signal
@ Signal
Definition: TrackUnit.h:73
TInterface::TimetableChangedFlag
bool TimetableChangedFlag
true when a timetable in the editor has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:982
TInterface::SaveTimetableToErrorFile
bool SaveTimetableToErrorFile(int Caller, std::ofstream &ErrorFile, AnsiString ErrorFileStr, AnsiString TimetableFileName)
Called when compiling the error log file, to save the loaded timetable if any and the timetable being...
Definition: InterfaceUnit.cpp:16417
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:678
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:15915
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:151
TInterface::TrainHeadCodeMenuItem
TMenuItem * TrainHeadCodeMenuItem
Definition: InterfaceUnit.h:458
TTrainController::TrainDataVector
TTrainDataVector TrainDataVector
vector containing the internal timetable
Definition: TrainUnit.h:795
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:10948
TTrain::ExitTimeHalf
TDateTime ExitTimeHalf
Definition: TrainUnit.h:409
Exited
@ Exited
Definition: TrainUnit.h:80
TInterface::OutputLog2
TLabel * OutputLog2
Definition: InterfaceUnit.h:292
TInterface::TTClockAdjustWarningLabel
TLabel * TTClockAdjustWarningLabel
Definition: InterfaceUnit.h:229
TInterface::SpeedButton74
TSpeedButton * SpeedButton74
Definition: InterfaceUnit.h:577
TInterface::ScreenRightButtonClick
void __fastcall ScreenRightButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8274
TInterface::PositionalPanel
TPanel * PositionalPanel
Definition: InterfaceUnit.h:383
TInterface::StepForwardMenuItemClick
void __fastcall StepForwardMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10069
TInterface::ErrorLog
void ErrorLog(int Caller, AnsiString Message)
The error logging routine, called when an error is detected.
Definition: InterfaceUnit.cpp:15315
TInterface::SpeedButton50
TSpeedButton * SpeedButton50
Definition: InterfaceUnit.h:553
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackElement.at(At)
Definition: TrackUnit.cpp:8927
TTrainController::LoadSessionTrains
void LoadSessionTrains(int Caller, std::ifstream &SessionFile)
load trains from a session file
Definition: TrainUnit.cpp:13894
TInterface::SpeedButton31
TSpeedButton * SpeedButton31
Definition: InterfaceUnit.h:534
TInterface::UserGraphicFoundFlag
bool UserGraphicFoundFlag
indicates that a user graphic item has been found when clicking on a build screen for moving
Definition: InterfaceUnit.h:980
TInterface::RouteCancelButtonClick
void __fastcall RouteCancelButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2088
TInterface::SpeedButton91
TSpeedButton * SpeedButton91
Definition: InterfaceUnit.h:594
TInterface::SelectedTrainID
int SelectedTrainID
used to store the train ID when right clicked for signaller control actions
Definition: InterfaceUnit.h:1071
TInterface::SpeedButton113
TSpeedButton * SpeedButton113
Definition: InterfaceUnit.h:616
TInterface::SpeedButton82
TSpeedButton * SpeedButton82
Definition: InterfaceUnit.h:585
TTextHandler::SelectTextPtrAt
TTextItem * SelectTextPtrAt(int Caller, int At)
return the text item at position 'At' in SelectTextVector (carries out range checking)
Definition: TextUnit.cpp:542
TInterface::SpeedButton132
TSpeedButton * SpeedButton132
Definition: InterfaceUnit.h:635
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:683
TInterface::FlashingGraphics
void FlashingGraphics(int Caller, TDateTime Now)
Deal with any warning graphics that need to flash (call on, signal stop, crash etc),...
Definition: InterfaceUnit.cpp:14763
TInterface::ScreenLeftButton
TBitBtn * ScreenLeftButton
Definition: InterfaceUnit.h:249
TTrain::StoppedAtLocation
bool StoppedAtLocation
Definition: TrainUnit.h:427
TTrainController::TContinuationTrainExpectationMultiMapIterator
TContinuationTrainExpectationMultiMap::iterator TContinuationTrainExpectationMultiMapIterator
iterator for the multimap
Definition: TrainUnit.h:682
TInterface::TTClockx16ButtonClick
void __fastcall TTClockx16ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11572
TInterface::BuildTrackMenuItem
TMenuItem * BuildTrackMenuItem
Definition: InterfaceUnit.h:419
TInterface::SaveOperatingImageMenuItem
TMenuItem * SaveOperatingImageMenuItem
Definition: InterfaceUnit.h:453
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:724
TInterface::NoRailway
bool NoRailway()
Returns true if there are no track elements and no text.
Definition: InterfaceUnit.cpp:18129
TInterface::AllEntriesTTListBox
TListBox * AllEntriesTTListBox
the list of service entries displayed on the left hand side of the timetable edit screen
Definition: InterfaceUnit.h:403
TInterface::CallingOnButtonClick
void __fastcall CallingOnButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8184
TInterface::SaveTTDialog
TSaveDialog * SaveTTDialog
Definition: InterfaceUnit.h:494
TInterface::DeleteOnePrefDirButtonClick
void __fastcall DeleteOnePrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1889
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:3718
TAllRoutes::NextRouteID
int NextRouteID
stores the value for the route ID number that is next to be built
Definition: TrackUnit.h:1569
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:468
TInterface::TTEntryChangedFlag
bool TTEntryChangedFlag
true when a timetable entry that is displayed in the timetable entry edit window has changed
Definition: InterfaceUnit.h:990
TInterface::HighlightPanel
TPanel * HighlightPanel
the orange bar that displays the current timetable entry in AllEntriesTTListBox
Definition: InterfaceUnit.h:369
TInterface::SpeedButton16
TSpeedButton * SpeedButton16
Definition: InterfaceUnit.h:519
TInterface::MoveTTEntryUpButtonClick
void __fastcall MoveTTEntryUpButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4139
TInterface::SpeedBottomLabel
TLabel * SpeedBottomLabel
Definition: InterfaceUnit.h:180
TTrainController::BFHigh
bool BFHigh
Definition: TrainUnit.h:733
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TInterface::TTClockResetButtonClick
void __fastcall TTClockResetButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11745
TInterface::ClockLabel
TLabel * ClockLabel
the timetable clock
Definition: InterfaceUnit.h:320
TInterface::SpeedButton43
TSpeedButton * SpeedButton43
Definition: InterfaceUnit.h:546
TTrain::LagEntryPos
int LagEntryPos
Definition: TrainUnit.h:327
TInterface::SetTrackBuildImages
void SetTrackBuildImages(int Caller)
Sets the left screen images (track linked or not, gaps set or not, locations named or not) during rai...
Definition: InterfaceUnit.cpp:15551
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:3696
TInterface::AddText
@ AddText
Definition: InterfaceUnit.h:880
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2058
TTrainController::UnexpectedExits
int UnexpectedExits
Definition: TrainUnit.h:769
TInterface::LoadTimetableMenuItemClick
void __fastcall LoadTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9510
TInterface::LengthEditKeyUp
void __fastcall LengthEditKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11358
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:10729
TInterface::OutputLog1
TLabel * OutputLog1
Definition: InterfaceUnit.h:291
TTrain::LeavingUnderSigControlAtContinuation
bool LeavingUnderSigControlAtContinuation
set when the train has reached an exit continuation when under signaller control, used to prevent the...
Definition: TrainUnit.h:355
TInterface::SpeedButton84
TSpeedButton * SpeedButton84
Definition: InterfaceUnit.h:587
TInterface::SpeedButton77
TSpeedButton * SpeedButton77
Definition: InterfaceUnit.h:580
TInterface::SpeedButton128
TSpeedButton * SpeedButton128
Definition: InterfaceUnit.h:631
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:841
TInterface::AddSubMinsBox
TEdit * AddSubMinsBox
the edit box that accepts minutes to add or subtract
Definition: InterfaceUnit.h:174
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:17090
TInterface::TTClockExitButton
TButton * TTClockExitButton
Definition: InterfaceUnit.h:217
TInterface::SpeedEditBox2
TEdit * SpeedEditBox2
Definition: InterfaceUnit.h:100
TInterface::MoveForwardsMenuItemClick
void __fastcall MoveForwardsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9791
TTrack::Down
@ Down
Definition: TrackUnit.h:523
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set TempMarker true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:5843
TInterface::TimetableNameLabel
TLabel * TimetableNameLabel
displays the current timetable name on the timetable edit panel
Definition: InterfaceUnit.h:310
TInterface::SpeedButton79
TSpeedButton * SpeedButton79
Definition: InterfaceUnit.h:582
TInterface::SpeedBottomLabel2
TLabel * SpeedBottomLabel2
Definition: InterfaceUnit.h:111
TInterface::SpeedButton51
TSpeedButton * SpeedButton51
Definition: InterfaceUnit.h:554
TInterface::IsPerformancePanelObscuringFloatingLabel
bool IsPerformancePanelObscuringFloatingLabel(int Caller)
Checked during operation, returns true if so and PerformancePanel removed - not used from v2....
Definition: InterfaceUnit.cpp:15394
TimeTimeLoc
@ TimeTimeLoc
Definition: TrainUnit.h:62
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1389
TInterface::TimetableChangedInAZOrderFlag
bool TimetableChangedInAZOrderFlag
used to give a warning message that changes will be discarded if proceed
Definition: InterfaceUnit.h:986
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement.
Definition: TrackUnit.cpp:5950
TInterface::AddTrackButtonClick
void __fastcall AddTrackButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:840
TInterface::SpeedButton92
TSpeedButton * SpeedButton92
Definition: InterfaceUnit.h:595
TInterface::DeleteMenuItemClick
void __fastcall DeleteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9372
TTrain::Derailed
bool Derailed
Definition: TrainUnit.h:427
TInterface::ConflictAnalysisButton
TButton * ConflictAnalysisButton
Definition: InterfaceUnit.h:232
TTextHandler::TextVectorPush
void TextVectorPush(int Caller, TTextItem Text)
push &Text onto TextVector & reset the size of the railway if necessary
Definition: TextUnit.cpp:485
TInterface::TTClockAdjButton
TBitBtn * TTClockAdjButton
Definition: InterfaceUnit.h:203
TInterface::PowerEditBoxKeyUp
void __fastcall PowerEditBoxKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:11225
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:15560
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:6306
TTrainController::SaveSessionLockedRoutes
void SaveSessionLockedRoutes(int Caller, std::ofstream &SessionFile)
save locked routes to a session file
Definition: TrainUnit.cpp:13944
TInterface::OpenHelpMenuItemClick
void __fastcall OpenHelpMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10960
TTrain::OriginalPowerAtRail
double OriginalPowerAtRail
new at v2.4.0 to store value before a failure so it can be restored from here when repaired
Definition: TrainUnit.h:396
TInterface::CheckPerformanceFile
bool CheckPerformanceFile(int Caller, std::ifstream &InFile)
Check the performance file embedded within a session file & return false for error,...
Definition: InterfaceUnit.cpp:17379
TInterface::TInterface
__fastcall TInterface(TComponent *Owner)
constructor
Definition: InterfaceUnit.cpp:80
TInterface::SpeedButton15
TSpeedButton * SpeedButton15
Definition: InterfaceUnit.h:518
clB4G5R5
#define clB4G5R5
Definition: GraphicUnit.h:244
Timetable
@ Timetable
Definition: TrainUnit.h:56
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:123
TInterface
Definition: InterfaceUnit.h:55
TInterface::RemoveTrainMenuItemClick
void __fastcall RemoveTrainMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10113
TInterface::RotRightMenuItemClick
void __fastcall RotRightMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8981
TTrain::AbleToMoveButForSignal
bool AbleToMoveButForSignal(int Caller)
Indicates that a train is only prevented from moving by a signal - used to allow appropriate popup me...
Definition: TrainUnit.cpp:6288
TTrainController::OpActionPanelVisible
bool OpActionPanelVisible
new v2.2.0 flag to prevent time to act functions when not visible
Definition: TrainUnit.h:730
TInterface::SaveInterface
void SaveInterface(int Caller, std::ofstream &SessionFile)
Save interface part of a session file.
Definition: InterfaceUnit.cpp:16004
TInterface::AcceptDragging
void __fastcall AcceptDragging(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept)
Definition: InterfaceUnit.cpp:5398
Parapet
@ Parapet
Definition: TrackUnit.h:64
TTrack::GapFlashRedPosition
int GapFlashRedPosition
TrackVectorPosition of the gap element that is flashing green or red.
Definition: TrackUnit.h:669
HiddenDisplay
TDisplay * HiddenDisplay
The object pointer for the internal hidden display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:15585
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TInterface::RouteFlashDuration
float RouteFlashDuration
duration of the route flash period
Definition: InterfaceUnit.h:1028
TInterface::SpeedButton4
TSpeedButton * SpeedButton4
Definition: InterfaceUnit.h:507
TTrainController::SignalStopWarning
bool SignalStopWarning
Definition: TrainUnit.h:722
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:277
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7693
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:15535
TDisplay::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: DisplayUnit.cpp:447
TTrain::SignallerStopBrakeRate
double SignallerStopBrakeRate
the train brake rate when stopping under signaller control
Definition: TrainUnit.h:391
TTrainController::SignallerTrainRemovedOnAutoSigsRoute
bool SignallerTrainRemovedOnAutoSigsRoute
true if train was on an AutoSigsRoute when removed by the signaller
Definition: TrainUnit.h:728
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:706
TTrainController::MRSLow
bool MRSLow
Definition: TrainUnit.h:733
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:681
TTrain::Crashed
bool Crashed
Definition: TrainUnit.h:427
TInterface::SpeedButton44
TSpeedButton * SpeedButton44
Definition: InterfaceUnit.h:547
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:145
TInterface::ScreenRightButton
TBitBtn * ScreenRightButton
Definition: InterfaceUnit.h:248
TTrain::HeadCodePosition
Graphics::TBitmap * HeadCodePosition[4]
Set from the HeadCodeGrPtr[4] pointer values, HeadCodePosition[0] is always the front,...
Definition: TrainUnit.h:441
TInterface::SigPrefButtonClick
void __fastcall SigPrefButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2014
TInterface::OAListBox
TListBox * OAListBox
Operator action list, sits inside OperatorActionPanel and lists trains in ascending order of time to ...
Definition: InterfaceUnit.h:405
TTrain::TrainID
int TrainID
the train's identification number
Definition: TrainUnit.h:330
TInterface::SaveTTButton
TButton * SaveTTButton
Definition: InterfaceUnit.h:144
TUtilities::CheckStringDouble
bool CheckStringDouble(AnsiString &DoubleString)
checks the string represents a valid double value, returns true for success. Added at v2....
Definition: Utilities.cpp:327
TInterface::SpeedButton63
TSpeedButton * SpeedButton63
Definition: InterfaceUnit.h:566
TRailGraphics::bmLightBlueRect
Graphics::TBitmap * bmLightBlueRect
Definition: GraphicUnit.h:522
TInterface::NonSigRouteStartMarker
TGraphicElement * NonSigRouteStartMarker
Definition: InterfaceUnit.h:1109
clB3G3R3
#define clB3G3R3
Definition: GraphicUnit.h:186
TInterface::SpeedButton53
TSpeedButton * SpeedButton53
Definition: InterfaceUnit.h:556
TInterface::SpeedButton107
TSpeedButton * SpeedButton107
Definition: InterfaceUnit.h:610
TTrainController::TrainVectorAt
TTrain & TrainVectorAt(int Caller, int VecPos)
Return a reference to the train at position VecPos in the TrainVector, carries out range checking on ...
Definition: TrainUnit.cpp:14220
TInterface::EditMenuClick
void __fastcall EditMenuClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8649
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:10656
TInterface::ModeMenu
TMenuItem * ModeMenu
Definition: InterfaceUnit.h:418
TInterface::SpeedButton112
TSpeedButton * SpeedButton112
Definition: InterfaceUnit.h:615
TInterface::MTBFEditBoxClick
void __fastcall MTBFEditBoxClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12056
TInterface::TEVPtr
TTEVPtr TEVPtr
Definition: InterfaceUnit.h:1132
TInterface::MasterClock
TTimer * MasterClock
the program clock (not the timetable clock)
Definition: InterfaceUnit.h:498
TInterface::OutputLog6MouseDown
void __fastcall OutputLog6MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10889
TRailGraphics::SpeedBut70GrndBlackGlyph
Graphics::TBitmap * SpeedBut70GrndBlackGlyph
Definition: GraphicUnit.h:1047
TTrainController::NumFailures
int NumFailures
Definition: TrainUnit.h:770
TInterface::CreateEditTTTitle
AnsiString CreateEditTTTitle
the title of the timetable currently being edited - i.e. the filename without the '....
Definition: InterfaceUnit.h:901
TInterface::AboutMenuItemClick
void __fastcall AboutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10939
TInterface::SelectStartPair
THVPair SelectStartPair
'Select' menu items
Definition: InterfaceUnit.h:1111
TTrainController::TOpTimeToActMultiMapIterator
TOpTimeToActMultiMap::iterator TOpTimeToActMultiMapIterator
Definition: TrainUnit.h:714
TInterface::SpeedButton6
TSpeedButton * SpeedButton6
Definition: InterfaceUnit.h:509
TTrack
Definition: TrackUnit.h:463
TInterface::OperatorActionPanelStartDrag
void __fastcall OperatorActionPanelStartDrag(TObject *Sender, TDragObject *&DragObject)
Definition: InterfaceUnit.cpp:5473
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:753
TInterface::OperateRailwayMenuItem
TMenuItem * OperateRailwayMenuItem
Definition: InterfaceUnit.h:423
TInterface::SaveRailwayTBPButton
TBitBtn * SaveRailwayTBPButton
Save button on TrackBuildPanel.
Definition: InterfaceUnit.h:72
TTrain::ExitSpeedFull
double ExitSpeedFull
speed when leaving the next element
Definition: TrainUnit.h:379
TInterface::MTBFLabel
TLabel * MTBFLabel
Definition: InterfaceUnit.h:481
TInterface::SelectBitmap
Graphics::TBitmap * SelectBitmap
the graphic defined by Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1033
TInterface::PreventGapOffsetResetting
bool PreventGapOffsetResetting
during gap setting gaps are highlighted in turn for the user to select the matching gap,...
Definition: InterfaceUnit.h:952
TInterface::TakeSignallerControlMenuItem
TMenuItem * TakeSignallerControlMenuItem
Definition: InterfaceUnit.h:459
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TInterface::Pasting
@ Pasting
Definition: InterfaceUnit.h:881
TInterface::AddTextButton
TBitBtn * AddTextButton
Definition: InterfaceUnit.h:65
TInterface::LoadRailwayMenuItem
TMenuItem * LoadRailwayMenuItem
Definition: InterfaceUnit.h:409
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TInterface::CrashImage
TImage * CrashImage
Definition: InterfaceUnit.h:262
TTrainController::RandomFailureCounter
unsigned int RandomFailureCounter
Definition: TrainUnit.h:785
TInterface::SpeedButton123
TSpeedButton * SpeedButton123
Definition: InterfaceUnit.h:626
TInterface::USERGRAPHICS_DIR_NAME
static const UnicodeString USERGRAPHICS_DIR_NAME
Definition: InterfaceUnit.h:867
TInterface::mbLeftDown
bool mbLeftDown
true when the left mouse button is down
Definition: InterfaceUnit.h:944
TInterface::SpeedButton115
TSpeedButton * SpeedButton115
Definition: InterfaceUnit.h:618
TInterface::ProgramVersion
UnicodeString ProgramVersion
Definition: InterfaceUnit.h:853
TInterface::TTClockResetButton
TButton * TTClockResetButton
Definition: InterfaceUnit.h:218
TUtilities::CheckAndReadFileInt
bool CheckAndReadFileInt(std::ifstream &InFile, int Lowest, int Highest, int &OutInt)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success ...
Definition: Utilities.cpp:251
TInterface::TempCursor
TCursor TempCursor
stores the screen cursor while a temporary cursor (ususlly an hourglass) is displayed
Definition: InterfaceUnit.h:1098
Interface
TInterface * Interface
Definition: InterfaceUnit.cpp:67
TInterface::SpeedButton61
TSpeedButton * SpeedButton61
Definition: InterfaceUnit.h:564
TDisplay::HideWarningLog
void HideWarningLog(int Caller)
Hide all the warnings from the top part of the screen - for timetable clock adjustment.
Definition: DisplayUnit.cpp:475
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:126
TUtilities::DecimalPoint
char DecimalPoint
added at v2.4.0 so can use the local value in loaded session files
Definition: Utilities.h:45
TInterface::ConstructPrefDir
TOnePrefDir * ConstructPrefDir
the Pref Dir under construction
Definition: InterfaceUnit.h:1118
TInterface::SpeedButton81
TSpeedButton * SpeedButton81
Definition: InterfaceUnit.h:584
TInterface::SigsOnLeftImage1
TImage * SigsOnLeftImage1
Definition: InterfaceUnit.h:279
TInterface::BuildTrackMenuItemClick
void __fastcall BuildTrackMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:823
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2596
TInterface::ClearandRebuildRailway
void ClearandRebuildRailway(int Caller)
Clear screen and rebuild it from stored data, uses HiddenScreen to avoid flicker.
Definition: InterfaceUnit.cpp:12274
TInterface::DisplayOneTTLineInPanel
void DisplayOneTTLineInPanel(int Caller, AnsiString Data, bool ServiceEntry)
Display a line from the TimetableEditVector (consists of a series of AnsiStrings, each of which repre...
Definition: InterfaceUnit.cpp:5178
TInterface::PlanPrefDirsMenuItem
TMenuItem * PlanPrefDirsMenuItem
Definition: InterfaceUnit.h:420
TInterface::AreAnyTimesInCurrentEntry
bool AreAnyTimesInCurrentEntry()
Search the timetable entry pointed to by TTCurrentEntryPtr and if any times (HH:MM) are present retur...
Definition: InterfaceUnit.cpp:5258
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:7835
TInterface::AutoRouteStartMarker
TGraphicElement * AutoRouteStartMarker
Definition: InterfaceUnit.h:1109
TInterface::RestoreTTButtonClick
void __fastcall RestoreTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4300
TInterface::SaveTTButtonClick
void __fastcall SaveTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3928
TInterface::FormCreate
void __fastcall FormCreate(TObject *Sender)
Definition: InterfaceUnit.cpp:719
TGraphicElement::SetSourceRect
void SetSourceRect(int Left, int Top)
Set SourceRect member values from those supplied and existing Width & Height - ensure this is only ca...
Definition: TrackUnit.h:373
TTrack::SelectPush
void SelectPush(TTrackElement TrackElement)
Store a TrackElement in the SelectVector.
Definition: TrackUnit.h:820
TAllRoutes::SignallerRemovedTrainAutoRoute
TOneRoute SignallerRemovedTrainAutoRoute
if train was on an AutoSigsRoute when removed then this stores the route so that signals can be reset
Definition: TrackUnit.h:1575
TInterface::SpeedButton7
TSpeedButton * SpeedButton7
Definition: InterfaceUnit.h:510
TTrainController::MassHigh
bool MassHigh
Definition: TrainUnit.h:733
TInterface::TimetablePanel
TPanel * TimetablePanel
'Create a timetable'/'Edit a timetable' panel that contains the topmost buttons (show/hide & exit)
Definition: InterfaceUnit.h:360
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:1823
TTrain::PlotTrainWithNewBackgroundColour
void PlotTrainWithNewBackgroundColour(int Caller, TColor NewBackgroundColour, TDisplay *Disp)
Changes the train's background colour (e.g. to pale green if stopped at a station) Note that this use...
Definition: TrainUnit.cpp:3255
TInterface::LoadSessionMenuItem
TMenuItem * LoadSessionMenuItem
Definition: InterfaceUnit.h:413
TInterface::SpeedButton69
TSpeedButton * SpeedButton69
Definition: InterfaceUnit.h:572
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:131
TInterface::OutputLog5MouseDown
void __fastcall OutputLog5MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10880
TInterface::ErrorButton
TBitBtn * ErrorButton
the 'Press to exit' button on the error screen
Definition: InterfaceUnit.h:256
TInterface::SpeedButton24
TSpeedButton * SpeedButton24
Definition: InterfaceUnit.h:527
TInterface::WarningFlash
bool WarningFlash
toggles on and off automatically at a cycle of about 0.5 sec, used to drive the warning icons during ...
Definition: InterfaceUnit.h:992
TInterface::CurrentSpeedButton
TSpeedButton * CurrentSpeedButton
stores the selected track build element button during railway building
Definition: InterfaceUnit.h:1129
TInterface::MainScreenMouseDown
void __fastcall MainScreenMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:5494
TTrain::ExitTimeFull
TDateTime ExitTimeFull
times used in SetTrainMovementValues corresponding to the next element the train runs on
Definition: TrainUnit.h:409
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:156
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:689
TInterface::TotalTicks
unsigned int TotalTicks
total clock ticks
Definition: InterfaceUnit.h:1039
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2281
TInterface::SpeedTopLabel2
TLabel * SpeedTopLabel2
Definition: InterfaceUnit.h:110
SignallerChangeDirection
@ SignallerChangeDirection
Definition: TrainUnit.h:51
TRailGraphics::GridBitmap
Graphics::TBitmap * GridBitmap
Definition: GraphicUnit.h:892
TInterface::PowerBottomLabel
TLabel * PowerBottomLabel
Definition: InterfaceUnit.h:188
TInterface::PasteMenuItem
TMenuItem * PasteMenuItem
Definition: InterfaceUnit.h:436
TTextHandler::EnterAndDisplayNewText
void EnterAndDisplayNewText(int Caller, TTextItem Text, int HPos, int VPos)
add Text to TextVector and display it on the screen
Definition: TextUnit.cpp:179
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:10444
TInterface::CreateEditTTFileName
AnsiString CreateEditTTFileName
the full path and filename of the timetable file
Definition: InterfaceUnit.h:899
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:11201
TInterface::PerformanceLogButtonClick
void __fastcall PerformanceLogButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2110
TTrainController::CheckSessionContinuationAutoSigEntries
bool CheckSessionContinuationAutoSigEntries(int Caller, std::ifstream &SessionFile)
Part of the session file integrity check for ContinuationAutoSigEntries, true for success.
Definition: TrainUnit.cpp:14066
IDInt
Definition: TrackUnit.h:412
TInterface::SelectLengthsMenuItemClick
void __fastcall SelectLengthsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9391
TInterface::NewSelectBitmapHLoc
int NewSelectBitmapHLoc
the new (during & at end of moving) HLoc value of Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1047
TInterface::LoadUserGraphic
void LoadUserGraphic(int Caller)
Load a user-defined graphic (bmp, gif, jpg, png).
Definition: InterfaceUnit.cpp:18356
TInterface::TTCurrentEntryPtr
TTEVPtr TTCurrentEntryPtr
Definition: InterfaceUnit.h:1132
TRunningEntry
TRunningEntry
contains status info for each train
Definition: TrainUnit.h:79
TInterface::OutputLog6
TLabel * OutputLog6
Definition: InterfaceUnit.h:296
TUtilities
Definition: Utilities.h:36
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:3965
TInterface::CreateTimetableMenuItemClick
void __fastcall CreateTimetableMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2975
TInterface::ExportTTButtonClick
void __fastcall ExportTTButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4383
TDisplay
Definition: DisplayUnit.h:48
TInterface::SpeedButton9
TSpeedButton * SpeedButton9
Definition: InterfaceUnit.h:512
TInterface::TTClockxEighthButtonClick
void __fastcall TTClockxEighthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11648
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:8674
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:143
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:787
TInterface::Text_X
int Text_X
the 'X' pixel value for an item of text
Definition: InterfaceUnit.h:1081
TInterface::SpeedVariableLabel
TLabel * SpeedVariableLabel
Definition: InterfaceUnit.h:181
TInterface::SpeedButton49
TSpeedButton * SpeedButton49
Definition: InterfaceUnit.h:552
TTrain::StoppedWithoutPower
bool StoppedWithoutPower
Definition: TrainUnit.h:428
TInterface::PowerVariableLabel
TLabel * PowerVariableLabel
Definition: InterfaceUnit.h:189
TActionEventType
TActionEventType
Used for reporting error conditions & warnings.
Definition: TrainUnit.h:39
TInterface::GapsNotSetImage
TImage * GapsNotSetImage
Definition: InterfaceUnit.h:276
TInterface::Level1Mode
enum TInterface::TLevel1Mode Level1Mode
TInterface::CallLogTickerLabel
TLabel * CallLogTickerLabel
diagnostic label displaying the call log depth, made visible by ctrl+ alt+ 2
Definition: InterfaceUnit.h:318
TInterface::TimetableEditVector
TTimetableEditVector TimetableEditVector
Definition: InterfaceUnit.h:1135
TTrainController::TrainExistsAtIdent
bool TrainExistsAtIdent(int Caller, int TrainID)
new at v2.4.0 return true if find the train (added at v2.4.0 as can select a removed train in OAListB...
Definition: TrainUnit.cpp:8535
SignallerJoin
@ SignallerJoin
Definition: TrainUnit.h:50
TTrain::StepForwardFlag
bool StepForwardFlag
set when the signaller command to step forward one element has been given
Definition: TrainUnit.h:363
TInterface::SaveRailwayDialog
TSaveDialog * SaveRailwayDialog
Definition: InterfaceUnit.h:493
TInterface::TTClockAdjustWarningPanel
TPanel * TTClockAdjustWarningPanel
Definition: InterfaceUnit.h:212
TInterface::TrainTTInfoOnOffMenuItemClick
void __fastcall TrainTTInfoOnOffMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:5373
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:95
TTrainController::Operate
void Operate(int Caller)
called every clock tick to introduce new trains and update existing trains
Definition: TrainUnit.cpp:7847
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:151
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:878
TTrain::PowerAtRail
double PowerAtRail
in Watts (taken as 80% of the train's Gross Power, i.e. that entered by the user)
Definition: TrainUnit.h:394
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:667
TAllRoutes::LevelCrossingBarrierDownDelay
const float LevelCrossingBarrierDownDelay
the full value in seconds for which the level crossing flashes prior to opening to trains
Definition: TrackUnit.h:1563
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1556
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:154
TInterface::SetSaveMenuAndButtons
void SetSaveMenuAndButtons(int Caller)
Called during the ClockTimer2 function to set screen boundaries, buttons & menu items.
Definition: InterfaceUnit.cpp:15020
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TInterface::TIMETABLE_DIR_NAME
static const UnicodeString TIMETABLE_DIR_NAME
Definition: InterfaceUnit.h:862
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:128
TInterface::SaveImageAndPrefDirsMenuItem
TMenuItem * SaveImageAndPrefDirsMenuItem
Definition: InterfaceUnit.h:452
TInterface::LoadRailwayMenuItemClick
void __fastcall LoadRailwayMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2193
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6550
TInterface::FormKeyUp
void __fastcall FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
Definition: InterfaceUnit.cpp:10830
TInterface::CopyTTEntryKeyFlag
bool CopyTTEntryKeyFlag
Definition: InterfaceUnit.h:1007
TTrainDataEntry::TrainOperatingDataVector
TTrainOperatingDataVector TrainOperatingDataVector
operating information for the train including all its repeats
Definition: TrainUnit.h:197
TInterface::OutputLog9MouseDown
void __fastcall OutputLog9MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10919
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:544
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:145
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:787
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1375
TInterface::SpeedButton80
TSpeedButton * SpeedButton80
Definition: InterfaceUnit.h:583
TTrain::IsThereAnAdjacentTrain
bool IsThereAnAdjacentTrain(int Caller, TTrain *&TrainToBeJoinedBy)
Definition: TrainUnit.cpp:4702
TInterface::ApproachLocking
void ApproachLocking(int Caller, TDateTime Now)
Function that deals with approach locking during ClockTimer2 function.
Definition: InterfaceUnit.cpp:14030
TInterface::TimetableTitle
AnsiString TimetableTitle
the titles of the loaded railway and loaded timetable, i.e. the filenames without the extension
Definition: InterfaceUnit.h:913
TInterface::BlackBgndMenuItemClick
void __fastcall BlackBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10983
TInterface::SpeedButton114
TSpeedButton * SpeedButton114
Definition: InterfaceUnit.h:617
TInterface::Deleting
@ Deleting
Definition: InterfaceUnit.h:881
TInterface::RestoreAllDefaultLengthsButton
TBitBtn * RestoreAllDefaultLengthsButton
Definition: InterfaceUnit.h:76
TInterface::ClearAllMenuItemClick
void __fastcall ClearAllMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2904
TUtilities::EventLog
std::deque< AnsiString > EventLog
event store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:57
TInterface::MoveTTEntryUpKeyFlag
bool MoveTTEntryUpKeyFlag
Definition: InterfaceUnit.h:1005
TActionVectorEntry::FormatType
TTimetableFormatType FormatType
defines the timetable action type
Definition: TrainUnit.h:110
TInterface::TextBox
TEdit * TextBox
the edit box that accepts text to be added
Definition: InterfaceUnit.h:87
TGraphicElement::GetHPos
int GetHPos()
Definition: TrackUnit.h:362
TInterface::SpeedButton133
TSpeedButton * SpeedButton133
Definition: InterfaceUnit.h:636
TOnePrefDir::SearchVectorSize
unsigned int SearchVectorSize() const
Return the vector size.
Definition: TrackUnit.h:1268
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:639
TTrainController::TimetableStartTime
TDateTime TimetableStartTime
the start time of the current timetable
Definition: TrainUnit.h:637
TTrainController::UnplotTrains
void UnplotTrains(int Caller)
unplot all trains from screen
Definition: TrainUnit.cpp:8190
TInterface::SpeedButton18
TSpeedButton * SpeedButton18
Definition: InterfaceUnit.h:521
TInterface::ScreenGridFlag
bool ScreenGridFlag
true when the screen grid is displayed
Definition: InterfaceUnit.h:960
TInterface::InfoCaptionStore
AnsiString InfoCaptionStore
temporary store for the information panel caption
Definition: InterfaceUnit.h:907
TRailGraphics::smBrightGreen
Graphics::TBitmap * smBrightGreen
Definition: GraphicUnit.h:870
TInterface::CopiedEntryFlag
bool CopiedEntryFlag
true when CopiedEntryStr holds a timetable entry in the timetable editor
Definition: InterfaceUnit.h:930
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:13556
TInterface::SpeedButton89
TSpeedButton * SpeedButton89
Definition: InterfaceUnit.h:592
TTrainController::EarlyArrivals
int EarlyArrivals
Definition: TrainUnit.h:755
TInterface::AnyTTKeyFlagSet
bool AnyTTKeyFlagSet()
Definition: InterfaceUnit.h:1145
TTrainController::CreateFormattedTimetable
void CreateFormattedTimetable(int Caller, AnsiString RailwayTitle, AnsiString TimetableTitle, AnsiString CurDir)
Examines the internal timetable (TrainDataVector) and creates from it a chronological (....
Definition: TrainUnit.cpp:14233
TInterface::SetTopIndex
void SetTopIndex(int Caller)
This used in timetable functions when shift keys pressed to make sure that the highlighted entry rema...
Definition: InterfaceUnit.cpp:12252
TTrack::RouteFlashFlag
bool RouteFlashFlag
true while a route is flashing prior to being set
Definition: TrackUnit.h:657
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:11660
TInterface::PowerToggleButtonClick
void __fastcall PowerToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11204
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1173
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:149
TInterface::SpeedButton46
TSpeedButton * SpeedButton46
Definition: InterfaceUnit.h:549
Points
@ Points
Definition: TrackUnit.h:63
TTrainController::TotLatePassMins
float TotLatePassMins
Definition: TrainUnit.h:750
TTrainController::StripSpaces
void StripSpaces(int Caller, AnsiString &Input)
Strip both leading and trailing spaces at ends of Input and spaces before and after all commas and se...
Definition: TrainUnit.cpp:12630
TInterface::Delay
void Delay(int Caller, double Msec)
Delays operation for the set time in milliseconds.
Definition: InterfaceUnit.cpp:12642
TTrain::JoinedOtherTrainFlag
bool JoinedOtherTrainFlag
true when the train has joined another train following an 'Fjo' timetable command or a signaller join...
Definition: TrainUnit.h:351
TTrainController::OpActionPanelHintDelayCounter
unsigned int OpActionPanelHintDelayCounter
new v2.2.0 on start operation delays the op action panel headcode display for about 3 secs while hint...
Definition: TrainUnit.h:783
TTrainController::BFLow
bool BFLow
Definition: TrainUnit.h:733
TInterface::OutputLog7
TLabel * OutputLog7
Definition: InterfaceUnit.h:297
TTrainController::TotArrDepPass
int TotArrDepPass
Definition: TrainUnit.h:768
TInterface::LastNonCtrlOrShiftKeyDown
int LastNonCtrlOrShiftKeyDown
value of last key (other than Ctrl or Shift) pressed down - to prevent repeated FormKeyDown calls fro...
Definition: InterfaceUnit.h:1045
SignallerPassRedSignal
@ SignallerPassRedSignal
Definition: TrainUnit.h:51
TRailGraphics::ChangeForegroundColour
void ChangeForegroundColour(int Caller, Graphics::TBitmap *BitmapIn, Graphics::TBitmap *BitmapOut, TColor NewForegroundColour, TColor BackgroundColour)
Definition: GraphicUnit.cpp:3291
TInterface::TextItem
int TextItem
used to store a single item of text
Definition: InterfaceUnit.h:1087
TInterface::UserGraphicButtonClick
void __fastcall UserGraphicButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12078
TInterface::OriginalTimetableEditVector
TTimetableEditVector OriginalTimetableEditVector
the complete timetable as a list of AnsiStrings for use in edit timetable functions
Definition: InterfaceUnit.h:1135
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1569
TInterface::PresetAutoSigRoutesButtonClick
void __fastcall PresetAutoSigRoutesButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11786
TRailGraphics::SpeedBut68GrndBlackGlyph
Graphics::TBitmap * SpeedBut68GrndBlackGlyph
Definition: GraphicUnit.h:1045
TTrain::SignallerRemoved
bool SignallerRemoved
set when removed under signaller control to force a removal from the display at the next clock tick
Definition: TrainUnit.h:359
TTrain::FrontCodePtr
Graphics::TBitmap * FrontCodePtr
points to the front headcode segment, this is set to red or blue depending on TrainMode
Definition: TrainUnit.h:445
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:14895
Continuation
@ Continuation
Definition: TrackUnit.h:63
TInterface::ScreenUpButton
TBitBtn * ScreenUpButton
Definition: InterfaceUnit.h:250
TInterface::TTServiceSyntaxCheckButton
TButton * TTServiceSyntaxCheckButton
Definition: InterfaceUnit.h:142
TTrainController::CallOnWarning
bool CallOnWarning
Definition: TrainUnit.h:722
TInterface::SetLengthsButton
TBitBtn * SetLengthsButton
Definition: InterfaceUnit.h:70
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
GraphicUnit.h
TInterface::AppActivate
void __fastcall AppActivate(TObject *Sender)
Definition: InterfaceUnit.cpp:770
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3326
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5351
TInterface::AddTextButtonClick
void __fastcall AddTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:979
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TInterface::ReselectMenuItemClick
void __fastcall ReselectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8692
TInterface::SpeedButton94
TSpeedButton * SpeedButton94
Definition: InterfaceUnit.h:597
TInterface::SaveTTAsKeyFlag
bool SaveTTAsKeyFlag
Definition: InterfaceUnit.h:1016
TInterface::SaveTTEntryButtonClick
void __fastcall SaveTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3780
TInterface::TimetablePanelLabel
TLabel * TimetablePanelLabel
label to the left of TimetablePanel
Definition: InterfaceUnit.h:312
TTrack::PointFlashFlag
bool PointFlashFlag
true when points are flashing during manual change
Definition: TrackUnit.h:655
TTrainController::OnTimeDeps
int OnTimeDeps
Definition: TrainUnit.h:763
TTrain::RestoreTimetableLocation
AnsiString RestoreTimetableLocation
stores the location name at which signaller control is taken, to ensure that it is back at that locat...
Definition: TrainUnit.h:419
TInterface::SpeedButton40
TSpeedButton * SpeedButton40
Definition: InterfaceUnit.h:543
TTrainController::TimetableIntegrityCheck
bool TimetableIntegrityCheck(int Caller, char *FileName, bool GiveMessages, bool CheckLocationsExistInRailway)
Checks overall timetable integrity, calls many other specific checking functions, returns true for su...
Definition: TrainUnit.cpp:8857
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TDisplay::Left
int Left()
Return the left pixel position of the screen.
Definition: DisplayUnit.h:114
TTrain::SignallerMaxSpeed
int SignallerMaxSpeed
maximum train speed under signaller control (in km/h)
Definition: TrainUnit.h:323
TInterface::BufferAttentionImage
TImage * BufferAttentionImage
Definition: InterfaceUnit.h:260
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:10487
TTrainController::SendPerformanceSummary
void SendPerformanceSummary(int Caller, std::ofstream &PerfFile)
At the end of operation a summary of overall performance is sent to the performance file by this func...
Definition: TrainUnit.cpp:16789
TInterface::OperatorActionButtonClick
void __fastcall OperatorActionButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11890
TInterface::SpeedEditBox
TEdit * SpeedEditBox
Definition: InterfaceUnit.h:178
TInterface::LoadRailwayDialog
TOpenDialog * LoadRailwayDialog
Definition: InterfaceUnit.h:487
TInterface::CopyMenuItem
TMenuItem * CopyMenuItem
Definition: InterfaceUnit.h:432
TInterface::ResetDefaultLengthButtonClick
void __fastcall ResetDefaultLengthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1488
RepairFailedTrain
@ RepairFailedTrain
Definition: TrainUnit.h:51
TInterface::NoOperMode
@ NoOperMode
Definition: InterfaceUnit.h:872
TInterface::ErrorLogCalledFlag
bool ErrorLogCalledFlag
true when an error has been thrown, stops repeated calls to ErrorLog and stops the MasterClockTimer f...
Definition: InterfaceUnit.h:938
TInterface::NextTTEntryKeyFlag
bool NextTTEntryKeyFlag
Definition: InterfaceUnit.h:1004
TInterface::RouteFlashStartTime
TDateTime RouteFlashStartTime
stores the starting time (timetable clock time) for route flashing
Definition: InterfaceUnit.h:1105
TInterface::PerformancePanelLabel
TLabel * PerformancePanelLabel
label at the top of PerformancePanel
Definition: InterfaceUnit.h:302
TInterface::BlueBgndMenuItemClick
void __fastcall BlueBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11058
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, bool ConsecSignals, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6097
TInterface::SetTrackLengths
void SetTrackLengths(int Caller, int Distance, int SpeedLimit)
Called during track building when setting distances, to calculate and set the individual track elemen...
Definition: InterfaceUnit.cpp:17802
TInterface::SpeedToggleButtonClick
void __fastcall SpeedToggleButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11095
TTrainController::ContinuationEntryFloatingTTString
AnsiString ContinuationEntryFloatingTTString(int Caller, TTrainDataEntry *TTDEPtr, int RepeatNumber, int IncrementalMinutes, int IncrementalDigits)
Build string for use in floating window for expected trains at continuations.
Definition: TrainUnit.cpp:8566
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:2962
TGraphicElement::GetVPos
int GetVPos()
Definition: TrackUnit.h:367
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1392
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:85
TTrain::SPADFlag
bool SPADFlag
set when running past a red signal without permission flags to indicate relevant stop conditions or p...
Definition: TrainUnit.h:425
TInterface::TTLabel5
TLabel * TTLabel5
Definition: InterfaceUnit.h:342
TInterface::HomeButtonClick
void __fastcall HomeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8580
TInterface::PointFlashStartTime
TDateTime PointFlashStartTime
stores the starting time (timetable clock time) for points flashing
Definition: InterfaceUnit.h:1103
TInterface::TTLabel7
TLabel * TTLabel7
Definition: InterfaceUnit.h:344
TInterface::RailwayWebSiteMenuItemClick
void __fastcall RailwayWebSiteMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:10975
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:609
TInterface::SpeedButton36
TSpeedButton * SpeedButton36
Definition: InterfaceUnit.h:539
TInterface::TTFirstServicePtr
TTEVPtr TTFirstServicePtr
Definition: InterfaceUnit.h:1132
TInterface::ClockTimer2
void ClockTimer2(int Caller)
The main loop, called every clock tick via MasterClockTimer.
Definition: InterfaceUnit.cpp:7608
TInterface::SpeedButton56
TSpeedButton * SpeedButton56
Definition: InterfaceUnit.h:559
TDisplay::PlotDashedRect
void PlotDashedRect(int Caller, TRect Rect)
Plot a dashed rectangle for the area defined by Rect, used when selecting display areas.
Definition: DisplayUnit.cpp:429
TInterface::NewTTEntryButtonClick
void __fastcall NewTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3355
TInterface::LoadSessionMenuItemClick
void __fastcall LoadSessionMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2890
TTrack::SelectVectorClear
void SelectVectorClear()
Definition: TrackUnit.h:825
TInterface::PerformanceFileName
AnsiString PerformanceFileName
full path and filename of the performance file
Definition: InterfaceUnit.h:911
TInterface::AutoSigsButton
TBitBtn * AutoSigsButton
Definition: InterfaceUnit.h:194
TInterface::PopupMenu
TPopupMenu * PopupMenu
Definition: InterfaceUnit.h:484
TInterface::LoadSessionFlag
bool LoadSessionFlag
true when a session load command has been given - implemented at next clock tick
Definition: InterfaceUnit.h:942
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:271
TInterface::NoTrackMode
@ NoTrackMode
Definition: InterfaceUnit.h:880
TInterface::TimetableValidFlag
bool TimetableValidFlag
indicates that a 'Validate timetable' button click in the timetable editor has succeeded
Definition: InterfaceUnit.h:984
TInterface::TimetableControlMenuItem
TMenuItem * TimetableControlMenuItem
Definition: InterfaceUnit.h:460
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:294
TUtilities::PerformanceFile
std::ofstream PerformanceFile
the file where the performance log for a particular period of operation is saved
Definition: Utilities.h:53
TInterface::TTLabel15
TLabel * TTLabel15
Definition: InterfaceUnit.h:351
TInterface::PreferredRoute
bool PreferredRoute
true when AutoSig or preferred route building selected during operation (always same state as ConsecS...
Definition: InterfaceUnit.h:948
TInterface::ConvertCRLFsToCommas
void ConvertCRLFsToCommas(int Caller, AnsiString &ConvStr)
Used in timetable editing functions to convert any CRLFs in intended service entries to commas.
Definition: InterfaceUnit.cpp:4959
TInterface::OutputLog2MouseDown
void __fastcall OutputLog2MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10851
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
TInterface::SpeedButton106
TSpeedButton * SpeedButton106
Definition: InterfaceUnit.h:609
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TInterface::LoadTimetableFromSessionFile
bool LoadTimetableFromSessionFile(int Caller, std::ifstream &SessionFile)
Loads timetable into memory from a session file, true if successful.
Definition: InterfaceUnit.cpp:16469
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:673
TInterface::SpeedButton125
TSpeedButton * SpeedButton125
Definition: InterfaceUnit.h:628
TInterface::SpeedButton21
TSpeedButton * SpeedButton21
Definition: InterfaceUnit.h:524
TUtilities::DateTimeStamp
AnsiString DateTimeStamp()
creates a string of the form 'dd/mm/yyyy hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:67
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:781
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4214
TInterface::SpeedButton64
TSpeedButton * SpeedButton64
Definition: InterfaceUnit.h:567
TInterface::AllEntriesTTListBoxMouseUp
void __fastcall AllEntriesTTListBoxMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:4582
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1583
TInterface::FontButton
TBitBtn * FontButton
Definition: InterfaceUnit.h:68
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:693
TInterface::NextTTEntryButtonClick
void __fastcall NextTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3277
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:198
TInterface::~TInterface
__fastcall ~TInterface()
destructor
Definition: InterfaceUnit.cpp:686
TInterface::CancelTTEntryButtonClick
void __fastcall CancelTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4263
TInterface::TTEVPtr
std::vector< AnsiString >::iterator TTEVPtr
typedef for pointers to entries in edit timetable functions
Definition: InterfaceUnit.h:891
TInterface::SaveHeaderMenu1Click
void __fastcall SaveHeaderMenu1Click(TObject *Sender)
Definition: InterfaceUnit.cpp:2832
TInterface::TTStartTimePtr
TTEVPtr TTStartTimePtr
Definition: InterfaceUnit.h:1132
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:617
TInterface::TTClockAdjPanel
TPanel * TTClockAdjPanel
Definition: InterfaceUnit.h:211
TInterface::BuildTrainDataVectorForLoadFile
bool BuildTrainDataVectorForLoadFile(int Caller, std::ifstream &TTBLFile, bool GiveMessages, bool CheckLocationsExistInRailway, bool SessionFile)
Convert a stored timetable file (either as a stand alone file or within a session file) to a loaded t...
Definition: InterfaceUnit.cpp:16680
TInterface::ConflictPanel
TPanel * ConflictPanel
Definition: InterfaceUnit.h:235
TInterface::CompileAllEntriesMemoAndSetPointers
void CompileAllEntriesMemoAndSetPointers(int Caller)
Used during timetable editing funtions to compile the list of entries into the left hand long entry w...
Definition: InterfaceUnit.cpp:4714
TInterface::CopiedEntryStr
AnsiString CopiedEntryStr
a timetable entry that has been copied
Definition: InterfaceUnit.h:897
TInterface::SpeedButton12
TSpeedButton * SpeedButton12
Definition: InterfaceUnit.h:515
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:17074
TInterface::SelectMenuItem
TMenuItem * SelectMenuItem
Definition: InterfaceUnit.h:429
TInterface::MoveTTEntryDownKeyFlag
bool MoveTTEntryDownKeyFlag
Definition: InterfaceUnit.h:1006
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1579
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4199
Connection
@ Connection
Definition: TrackUnit.h:73
TInterface::TTTextButtonClick
void __fastcall TTTextButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4422
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3303
TTrainController::TrainFailedWarning
bool TrainFailedWarning
Flags to enable the relevant warning graphics to flash at the left hand side of the screen.
Definition: TrainUnit.h:722
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1558
TInterface::LengthOKButton
TBitBtn * LengthOKButton
distance/speed setting buttons - left to right & top to bottom
Definition: InterfaceUnit.h:79
TTrain::NextTrainID
static int NextTrainID
the ID value to be used for the next train that is created, static so that it doesn't need an object ...
Definition: TrainUnit.h:287
TInterface::PreviousTTEntryButtonClick
void __fastcall PreviousTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3316
TInterface::UserGraphicButton
TBitBtn * UserGraphicButton
Definition: InterfaceUnit.h:81
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:14705
TInterface::Text_Y
int Text_Y
as above for 'Y'
Definition: InterfaceUnit.h:1083
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:16376
TInterface::DeleteTTEntryButton
TButton * DeleteTTEntryButton
Definition: InterfaceUnit.h:132
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TInterface::ReselectUserGraphicClick
void __fastcall ReselectUserGraphicClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12110
TInterface::TTClockAdd1mButtonClick
void __fastcall TTClockAdd1mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11725
TInterface::SubMinsButton
TButton * SubMinsButton
Definition: InterfaceUnit.h:141
TInterface::SpeedButton66
TSpeedButton * SpeedButton66
Definition: InterfaceUnit.h:569
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set TempMarker true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6023
TInterface::ValidateTimetableButtonClick
void __fastcall ValidateTimetableButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4083
TInterface::UserGraphicMoveVPos
int UserGraphicMoveVPos
used to store the original user graphic 'H' & 'V' positions for use during moving
Definition: InterfaceUnit.h:1093
TInterface::SpeedButton98
TSpeedButton * SpeedButton98
Definition: InterfaceUnit.h:601
TActionVectorEntry::LocationName
AnsiString LocationName
Definition: TrainUnit.h:96
TInterface::LoadTimetableMenuItem
TMenuItem * LoadTimetableMenuItem
Definition: InterfaceUnit.h:412
TInterface::SpeedButton95
TSpeedButton * SpeedButton95
Definition: InterfaceUnit.h:598
TInterface::LocationNameButtonClick
void __fastcall LocationNameButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1057
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5159
TInterface::SaveMenuItem
TMenuItem * SaveMenuItem
Definition: InterfaceUnit.h:411
TInterface::GapSetting
@ GapSetting
Definition: InterfaceUnit.h:880
TTrain::TimeTimeLocArrived
bool TimeTimeLocArrived
indicates whether has arrived (true) or not when ActionVectorEntryPtr->FormatType == TimeTimeLoc
Definition: TrainUnit.h:294
TInterface::ShowHideTTButton
TBitBtn * ShowHideTTButton
Definition: InterfaceUnit.h:123
TInterface::ScreenDownButton
TBitBtn * ScreenDownButton
Definition: InterfaceUnit.h:251
TTrain::LeadEntryPos
int LeadEntryPos
Definition: TrainUnit.h:327
TTrainController::LateArrivals
int LateArrivals
Definition: TrainUnit.h:758
TInterface::DeleteOnePrefDirButton
TBitBtn * DeleteOnePrefDirButton
Definition: InterfaceUnit.h:116
TInterface::PauseEntryTTClockSpeed
float PauseEntryTTClockSpeed
rate at which the timetable clock runs on entry to the adjust routine - to restore if cancelled
Definition: InterfaceUnit.h:1024
TTrainController::ReplotTrains
void ReplotTrains(int Caller, TDisplay *Disp)
plot all trains on the display
Definition: TrainUnit.cpp:8160
TInterface::MetreVariableLabel
TLabel * MetreVariableLabel
Definition: InterfaceUnit.h:102
TInterface::AllEntriesTTListBoxTopPosition
int AllEntriesTTListBoxTopPosition
stores the TopIndex property when keys are used to select items in the TT edit panel
Definition: InterfaceUnit.h:1043
TInterface::SigImagePanel
TPanel * SigImagePanel
new at v2.3.0 for handed signals
Definition: InterfaceUnit.h:386
TTrain::FloatingTimetableString
AnsiString FloatingTimetableString(int Caller, TActionVectorEntry *Ptr)
Used in the floating window to display the timetable.
Definition: TrainUnit.cpp:6485
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:643
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:15599
TInterface::CPGenFileButtonClick
void __fastcall CPGenFileButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:12207
TInterface::TTClockAdd10mButtonClick
void __fastcall TTClockAdd10mButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11705
TRailGraphics::SpeedBut73GrndBlackGlyph
Graphics::TBitmap * SpeedBut73GrndBlackGlyph
Definition: GraphicUnit.h:1050
TTrain::AValue
double AValue
this is a useful shorthand value in calculating speeds and transit times in SetTrainMovementValues [=...
Definition: TrainUnit.h:371
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:6510
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:2724
TTrainController::WriteTrainsToImage
void WriteTrainsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click) to write all trains to the image file.
Definition: TrainUnit.cpp:8175
TInterface::SpeedButton30
TSpeedButton * SpeedButton30
Definition: InterfaceUnit.h:533
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:130
TInterface::TTClockSpeedLabel
TLabel * TTClockSpeedLabel
Definition: InterfaceUnit.h:328
TTrack::FourAspectBuild
@ FourAspectBuild
Definition: TrackUnit.h:753
TInterface::SpeedButton146
TSpeedButton * SpeedButton146
Definition: InterfaceUnit.h:649
TTrainController::OpTimeToActMultiMapIterator
TOpTimeToActMultiMapIterator OpTimeToActMultiMapIterator
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:793
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:540
TInterface::NewEntryInPreparationFlag
bool NewEntryInPreparationFlag
true when a new timetable entry is being prepared in the timetable editor
Definition: InterfaceUnit.h:946
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TInterface::OAPanelLabel
TLabel * OAPanelLabel
Definition: InterfaceUnit.h:333
TInterface::GetVersion
UnicodeString GetVersion()
determined automatically from the project options 'Version Info'
Definition: InterfaceUnit.cpp:787
TInterface::OneEntryTimetableContents
AnsiString OneEntryTimetableContents
the current text in the large right hand timetable edit window
Definition: InterfaceUnit.h:909
TInterface::SelectRect
TRect SelectRect
the rectangle in HLoc & VLoc terms set in Edit->Select & Edit->Reselect
Definition: InterfaceUnit.h:1126
TTrain::ZeroPowerNoJoinedByMessage
bool ZeroPowerNoJoinedByMessage
Definition: TrainUnit.h:303
TInterface::LocationNameComboBox
TComboBox * LocationNameComboBox
the combobox that lists location names
Definition: InterfaceUnit.h:172
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:659
TInterface::ValidateTimetableKeyFlag
bool ValidateTimetableKeyFlag
Definition: InterfaceUnit.h:1014
TInterface::ExitOperationButton
TBitBtn * ExitOperationButton
Definition: InterfaceUnit.h:202
TTrain::CalcTimeToAct
float CalcTimeToAct(int Caller)
new v2.2.0 for operator action panel. Calculates the time left for operator action to avoid unnecessa...
Definition: TrainUnit.cpp:7584
TInterface::TTLabel6
TLabel * TTLabel6
Definition: InterfaceUnit.h:343
TInterface::SpeedButton97
TSpeedButton * SpeedButton97
Definition: InterfaceUnit.h:600
TTrainController::SaveSessionContinuationAutoSigEntries
void SaveSessionContinuationAutoSigEntries(int Caller, std::ofstream &SessionFile)
save ContinuationAutoSigEntries to a session file
Definition: TrainUnit.cpp:14026
TInterface::SignalStopImage
TImage * SignalStopImage
Definition: InterfaceUnit.h:264
TInterface::SpeedButton13
TSpeedButton * SpeedButton13
Definition: InterfaceUnit.h:516
TInterface::OutputLog9
TLabel * OutputLog9
Definition: InterfaceUnit.h:299
TInterface::SetCaption
void SetCaption(int Caller)
Sets the railway and timetable titles at the top of the screen.
Definition: InterfaceUnit.cpp:15418
TInterface::SpeedButton27
TSpeedButton * SpeedButton27
Definition: InterfaceUnit.h:530
TOnePrefDir::ExternalClearPrefDirAnd4MultiMap
void ExternalClearPrefDirAnd4MultiMap()
Empty the existing preferred direction vector & map - for use by other classes.
Definition: TrackUnit.h:1274
TInterface::SetInitialPrefDirModeEditMenu
void SetInitialPrefDirModeEditMenu()
Enables or disables the initial Edit mode submenu items in PrefDir mode.
Definition: InterfaceUnit.cpp:18104
TInterface::MainScreenMouseMove
void __fastcall MainScreenMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:7015
TInterface::DistanceContinuing
@ DistanceContinuing
Definition: InterfaceUnit.h:880
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:565
TInterface::CutTTEntryKeyFlag
bool CutTTEntryKeyFlag
Definition: InterfaceUnit.h:1008
TInterface::SigsOnLeftImage2
TImage * SigsOnLeftImage2
Definition: InterfaceUnit.h:280
TInterface::ChainEdit
TEdit * ChainEdit
Definition: InterfaceUnit.h:98
TInterface::SpeedButton109
TSpeedButton * SpeedButton109
Definition: InterfaceUnit.h:612
TInterface::CPAtLocCheckBox
TCheckBox * CPAtLocCheckBox
Definition: InterfaceUnit.h:243
TInterface::PasteTTEntryButtonClick
void __fastcall PasteTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3642
TInterface::SpeedButton100
TSpeedButton * SpeedButton100
Definition: InterfaceUnit.h:603
TInterface::TestFunction
void TestFunction()
Called for diagnostic purposes when keys CTRL ALT 4 pressed.
Definition: InterfaceUnit.cpp:18204
TInterface::ExportTTKeyFlag
bool ExportTTKeyFlag
Definition: InterfaceUnit.h:1018
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:9898
TTrain::FirstHalfMove
bool FirstHalfMove
true when the train is on the first half of an element when it displays as fully on two elements....
Definition: TrainUnit.h:349
TInterface::MovingTrainPresentOnFlashingRoute
bool MovingTrainPresentOnFlashingRoute(int Caller)
Examines a flashing route (i.e. one being set) and returns true if a moving train is detected on it a...
Definition: InterfaceUnit.cpp:12674
TInterface::Level2TrackMode
enum TInterface::TLevel2TrackMode Level2TrackMode
TInterface::SpeedButton65
TSpeedButton * SpeedButton65
Definition: InterfaceUnit.h:568
TInterface::DeleteTTEntryKeyFlag
bool DeleteTTEntryKeyFlag
Definition: InterfaceUnit.h:1010
TTrainController::LatePasses
int LatePasses
Definition: TrainUnit.h:760
TInterface::SaveRailwayBaseModeButton
TBitBtn * SaveRailwayBaseModeButton
Save button at the top left hand corner of the screen when no mode is selected.
Definition: InterfaceUnit.h:58
TInterface::SelectBiDirPrefDirsMenuItem
TMenuItem * SelectBiDirPrefDirsMenuItem
Definition: InterfaceUnit.h:439
TInterface::UserGraphicReselectPanel
TPanel * UserGraphicReselectPanel
Definition: InterfaceUnit.h:482
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:98
TInterface::RotLeftMenuItem
TMenuItem * RotLeftMenuItem
Definition: InterfaceUnit.h:475
TInterface::TTClockxQuarterButtonClick
void __fastcall TTClockxQuarterButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11629
TTrainController::SSHigh
bool SSHigh
Definition: TrainUnit.h:733
TInterface::TextOrUserGraphicGridVal
int TextOrUserGraphicGridVal
stores the text alignment grid value, cycles forwards through 1, 2, 4, 8 & 16 each time the text grid...
Definition: InterfaceUnit.h:1085
TimeLoc
@ TimeLoc
Definition: TrainUnit.h:62
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:210
TInterface::FileMenu
TMenuItem * FileMenu
Definition: InterfaceUnit.h:408
TTrainController::AvHoursIntValue
int AvHoursIntValue
Input in MTBFEditBox in timetable hours, min value is 1 and max is 10,000. Here because performance f...
Definition: TrainUnit.h:778
TTrainController::CrashedTrains
int CrashedTrains
Definition: TrainUnit.h:753
TInterface::OutputLog3MouseDown
void __fastcall OutputLog3MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
Definition: InterfaceUnit.cpp:10860
TInterface::SpeedConversionPanel
TPanel * SpeedConversionPanel
Definition: InterfaceUnit.h:105
TTrain::LogAction
void LogAction(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionType ActionType, AnsiString LocationName, TDateTime TimetableNonRepeatTime, bool Warning)
Send a message to the performance log and performance file, and if the message is flagged as a warnin...
Definition: TrainUnit.cpp:4785
TInterface::SpeedButton22
TSpeedButton * SpeedButton22
Definition: InterfaceUnit.h:525
TTextHandler::SaveText
void SaveText(int Caller, std::ofstream &VecFile)
save the railway's text to VecFile
Definition: TextUnit.cpp:319
TTrain::StoppedAtSignal
bool StoppedAtSignal
Definition: TrainUnit.h:427
TInterface::SpeedButton130
TSpeedButton * SpeedButton130
Definition: InterfaceUnit.h:633
TTrack::GetGapHLoc
int GetGapHLoc()
Definition: TrackUnit.h:756
TInterface::ResetDefaultLengthButton
TBitBtn * ResetDefaultLengthButton
Definition: InterfaceUnit.h:77
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise points: 0=set to ...
Definition: TrackUnit.h:139
TInterface::PauseEntryRestartTime
double PauseEntryRestartTime
time value of the timetable restart time (as a double) on entry to pause mode
Definition: InterfaceUnit.h:1021
TInterface::SelectBiDirPrefDirsMenuItemClick
void __fastcall SelectBiDirPrefDirsMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9419
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4094
TInterface::SigsOnRightImage2
TImage * SigsOnRightImage2
Definition: InterfaceUnit.h:282
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:699
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4091
TInterface::AddTrack
@ AddTrack
Definition: InterfaceUnit.h:880
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1670
TInterface::ClearAllMenuItem
TMenuItem * ClearAllMenuItem
Definition: InterfaceUnit.h:415
TTrainController::THCandTrainPosParam
std::pair< AnsiString, int > THCandTrainPosParam
Definition: TrainUnit.h:707
TInterface::SaveImageNoGridMenuItem
TMenuItem * SaveImageNoGridMenuItem
Definition: InterfaceUnit.h:450
TInterface::SelectMenuItemClick
void __fastcall SelectMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8665
TRailGraphics::SpeedBut74NormBlackGlyph
Graphics::TBitmap * SpeedBut74NormBlackGlyph
Definition: GraphicUnit.h:1043
TInterface::StartY
int StartY
the mouse position in terms of pixels when an item of text is being selected for moving
Definition: InterfaceUnit.h:1077
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:63
TInterface::UpdateOperatorActionPanel
void UpdateOperatorActionPanel(int Caller)
Called every 5 secs to update the panel (if visible)
Definition: InterfaceUnit.cpp:18302
TInterface::TextBoxKeyPress
void __fastcall TextBoxKeyPress(TObject *Sender, char &Key)
Definition: InterfaceUnit.cpp:1017
TInterface::SaveTimetableToSessionFile
bool SaveTimetableToSessionFile(int Caller, std::ofstream &SessionFile, AnsiString SessionFileStr)
Called during a session save to save the current timetable in the session file, true if successful.
Definition: InterfaceUnit.cpp:16352
TInterface::SpeedButton71
TSpeedButton * SpeedButton71
Definition: InterfaceUnit.h:574
TTrain::OpTimeToAct
float OpTimeToAct
in minutes: new at v2.2.0 for operator time to act panel. Calculated in UpdateTrain,...
Definition: TrainUnit.h:400
TInterface::DeleteAllPrefDirButtonClick
void __fastcall DeleteAllPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1858
Platform
@ Platform
Definition: TrackUnit.h:63
TInterface::RlyFile
bool RlyFile
indicates that a loaded railway file is ready for operation, i.e. is a valid .rly file
Definition: InterfaceUnit.h:954
TInterface::RestartSessionOperMode
@ RestartSessionOperMode
Definition: InterfaceUnit.h:850
TInterface::PreferredRouteFlag
bool PreferredRouteFlag
used to select either ConvertAndAddPreferredRouteSearchVector or ConvertAndAddNonPreferredRouteSearch...
Definition: InterfaceUnit.h:950
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:664
TInterface::TextMoveHPos
int TextMoveHPos
Definition: InterfaceUnit.h:1089
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4116
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:635
TInterface::PowerTopLabel
TLabel * PowerTopLabel
Definition: InterfaceUnit.h:187
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:675
TInterface::SpeedButton129
TSpeedButton * SpeedButton129
Definition: InterfaceUnit.h:632
TInterface::RepairFailedTrainMenuItem
TMenuItem * RepairFailedTrainMenuItem
Definition: InterfaceUnit.h:477
TUtilities::CheckAndCompareFileString
bool CheckAndCompareFileString(std::ifstream &InFile, AnsiString InString)
checks that the value is a string ('0' or CR accepted as delimiters) and is the same as InString,...
Definition: Utilities.cpp:413
TInterface::CutTTEntryButton
TButton * CutTTEntryButton
Definition: InterfaceUnit.h:130
TInterface::AZOrderKeyFlag
bool AZOrderKeyFlag
Definition: InterfaceUnit.h:1012
TInterface::MileEdit
TEdit * MileEdit
Definition: InterfaceUnit.h:97
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1180
TInterface::TTClockx8ButtonClick
void __fastcall TTClockx8ButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11553
TInterface::SetLevel2OperMode
void SetLevel2OperMode(int Caller)
Sets the Level2OperMode user mode, using the Level2OperMode variable to determine the mode.
Definition: InterfaceUnit.cpp:13891
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:8046
TInterface::RestoreTTButton
TButton * RestoreTTButton
Definition: InterfaceUnit.h:146
TTrain::TimetableFinished
bool TimetableFinished
set when there are no more timetable actions
Definition: TrainUnit.h:367
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1484
TInterface::EraseLocationNameText
bool EraseLocationNameText(int Caller, AnsiString Name, int &HPos, int &VPos)
Erase a location name (providing it exists in LocationNameMultiMap) from TextVector,...
Definition: InterfaceUnit.cpp:18146
TInterface::PrefDirKey
TImage * PrefDirKey
information panel displayed when setting preferred directions
Definition: InterfaceUnit.h:269
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TActionVectorEntry::Command
AnsiString Command
Definition: TrainUnit.h:96
TInterface::SpeedButton138
TSpeedButton * SpeedButton138
Definition: InterfaceUnit.h:641
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:701
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:147
TInterface::DeleteAllPrefDirButton
TBitBtn * DeleteAllPrefDirButton
Definition: InterfaceUnit.h:117
TInterface::SpeedButton117
TSpeedButton * SpeedButton117
Definition: InterfaceUnit.h:620
TTrain::SignallerStoppingFlag
bool SignallerStoppingFlag
set when the signaller stop command has been given
Definition: TrainUnit.h:361
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:141
TInterface::SpeedButton39
TSpeedButton * SpeedButton39
Definition: InterfaceUnit.h:542
TTrack::BuildBasicElementFromSpeedTag
TTrackElement BuildBasicElementFromSpeedTag(int Caller, int SpeedTag)
Return a basic track element from the SpeedTag new at v2.2.0 - needed because Interface doesn't have ...
Definition: TrackUnit.h:808
TInterface::TTStartTimeBox
TEdit * TTStartTimeBox
edit box that displays the timetable start time
Definition: InterfaceUnit.h:170
TInterface::AddPrefDirButtonClick
void __fastcall AddPrefDirButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1831
TInterface::ShiftKey
bool ShiftKey
true when the SHIFT key is pressed (see also CtrlKey)
Definition: InterfaceUnit.h:968
TTrainController::SigSLow
bool SigSLow
Message flags in TT checks to stop being given twice.
Definition: TrainUnit.h:733
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:527
TInterface::AddMinsButtonClick
void __fastcall AddMinsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3375
RemoveTrain
@ RemoveTrain
Definition: TrainUnit.h:50
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3203
TInterface::FontButtonClick
void __fastcall FontButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1762
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:98
TInterface::SigAspectButtonClick
void __fastcall SigAspectButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1723
TInterface::SetLevel2TrackMode
void SetLevel2TrackMode(int Caller)
Sets the Level2TrackMode user mode, using the Level2TrackMode variable to determine the mode.
Definition: InterfaceUnit.cpp:13267
TTrainController::SetWarningFlags
void SetWarningFlags(int Caller)
This sets all the warning flags (CrashWarning, DerailWarning etc) to their required states after a se...
Definition: TrainUnit.cpp:17040
TInterface::None
@ None
Definition: InterfaceUnit.h:885
TInterface::SpeedButton87
TSpeedButton * SpeedButton87
Definition: InterfaceUnit.h:590
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:111
TInterface::FormClose
void __fastcall FormClose(TObject *Sender, TCloseAction &Action)
Definition: InterfaceUnit.cpp:10285
TInterface::SigAspectButton
TBitBtn * SigAspectButton
Definition: InterfaceUnit.h:74
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:9371
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:647
TInterface::PreviousTTEntryKeyFlag
bool PreviousTTEntryKeyFlag
Definition: InterfaceUnit.h:1003
TInterface::CPEditDepRange
TEdit * CPEditDepRange
Definition: InterfaceUnit.h:245
TInterface::SpeedButton127
TSpeedButton * SpeedButton127
Definition: InterfaceUnit.h:630
TTrainController::TotEarlyPassMins
float TotEarlyPassMins
Definition: TrainUnit.h:747
TTrainController::OpTimeToActMultiMap
TOpTimeToActMultiMap OpTimeToActMultiMap
added v2.2.0 for Op time to act display
Definition: TrainUnit.h:791
TInterface::SelectBitmapMouseLocY
int SelectBitmapMouseLocY
see above
Definition: InterfaceUnit.h:1067
TTrain::BrakeRate
double BrakeRate
the current train brake rate
Definition: TrainUnit.h:389
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:147
TTrack::GapFlashFlag
bool GapFlashFlag
true when a pair of connected gaps is flashing
Definition: TrackUnit.h:645
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:536
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TInterface::StartX
int StartX
Definition: InterfaceUnit.h:1077
TrainUnit.h
TTrack::LevelCrossingBarrierUpFlashDuration
float LevelCrossingBarrierUpFlashDuration
duration of the flash period when level crossing closing to trains
Definition: TrackUnit.h:662
TTrainController::IncorrectExits
int IncorrectExits
Definition: TrainUnit.h:757
TUtilities::SetLocaleResultOK
bool SetLocaleResultOK
flag to indicate whether the call to setlocale() in InterfaceUnit.cpp succeeded or not
Definition: Utilities.h:42
TInterface::SelectLengthsFlag
bool SelectLengthsFlag
true when 'Set lengths &/or speeds' selected in the 'Edit' menu
Definition: InterfaceUnit.h:964
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:87
TRailGraphics::LockedRouteCancelPtr
Graphics::TBitmap * LockedRouteCancelPtr[10]
for locked route cancel graphic, 1 for each of 8 links, 0 & 5 included as for direction
Definition: GraphicUnit.h:1029
TInterface::TrackOKButton
TBitBtn * TrackOKButton
Definition: InterfaceUnit.h:64
TInterface::SpeedButton23
TSpeedButton * SpeedButton23
Definition: InterfaceUnit.h:526
TInterface::RailwayTitle
AnsiString RailwayTitle
Definition: InterfaceUnit.h:913
TDisplay::Rectangle
void Rectangle(int Caller, int HPos, int VPos, TColor Col, int Size, int Width)
Plot a rectangle at the defined position with colour Col & size defined by Size.
Definition: DisplayUnit.cpp:152
TInterface::SpeedButton20
TSpeedButton * SpeedButton20
Definition: InterfaceUnit.h:523
TInterface::CheckInterface
bool CheckInterface(int Caller, std::ifstream &SessionFile)
Check the interface part of a session file & return false for error, called during SessionFileIntegri...
Definition: InterfaceUnit.cpp:16118
TInterface::PreStart
@ PreStart
Definition: InterfaceUnit.h:872
AboutForm
TAboutForm * AboutForm
Definition: AboutUnit.cpp:47
TInterface::SpeedButton137
TSpeedButton * SpeedButton137
Definition: InterfaceUnit.h:640
TInterface::ExitTTModeButton
TBitBtn * ExitTTModeButton
Definition: InterfaceUnit.h:124
TTrain::SetTrainMovementValues
void SetTrainMovementValues(int Caller, int TrackVectorPosition, int EntryPos)
Calculates train speeds and times for the element that the train is about to enter....
Definition: TrainUnit.cpp:3292
TActionVectorEntry::Warning
bool Warning
if set triggers an alert in the warning panel when the action is reached
Definition: TrainUnit.h:100
TInterface::OverallSpeedLimit
int OverallSpeedLimit
and the overall speed limit, if the speed limits vary across the selection the value is set to -1
Definition: InterfaceUnit.h:1055
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:9832
TInterface::SpeedButton78
TSpeedButton * SpeedButton78
Definition: InterfaceUnit.h:581
TRailGraphics::SpeedBut75GrndBlackGlyph
Graphics::TBitmap * SpeedBut75GrndBlackGlyph
Definition: GraphicUnit.h:1052
TTrainDataEntry::ServiceReference
AnsiString ServiceReference
Definition: TrainUnit.h:179
TInterface::PowerEditBox
TEdit * PowerEditBox
Definition: InterfaceUnit.h:186
TInterface::TimetableHandler
void TimetableHandler()
Called during timetable editing whenever a change is made to the timetable, sets all the timetable bu...
Definition: InterfaceUnit.cpp:5001
TTrain::SignallerChangeTrainDirection
void SignallerChangeTrainDirection(int Caller)
Unplots & replots train, which checks for facing signal and sets StoppedAtSignal if req'd.
Definition: TrainUnit.cpp:6319
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:250
TInterface::CancelSelectionMenuItem
TMenuItem * CancelSelectionMenuItem
Definition: InterfaceUnit.h:440
TTrain::ZeroPowerNoRearSplitMessage
bool ZeroPowerNoRearSplitMessage
Definition: TrainUnit.h:301
TInterface::SpeedButton68
TSpeedButton * SpeedButton68
Definition: InterfaceUnit.h:571
TInterface::LoadSession
void LoadSession(int Caller)
Load a session file.
Definition: InterfaceUnit.cpp:15763
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:15639
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:16646
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TInterface::SigRouteStartMarker
TGraphicElement * SigRouteStartMarker
Definition: InterfaceUnit.h:1109
TInterface::SetGapsButtonClick
void __fastcall SetGapsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:958
TInterface::SignallerControlStopMenuItemClick
void __fastcall SignallerControlStopMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9996
TInterface::PrefDirSelecting
@ PrefDirSelecting
Definition: InterfaceUnit.h:876
TInterface::TimetableDialog
TOpenDialog * TimetableDialog
Definition: InterfaceUnit.h:489
TInterface::MissedTicks
unsigned int MissedTicks
missed clock ticks
Definition: InterfaceUnit.h:1041
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:9400
TInterface::MoveTTEntryUpButton
TButton * MoveTTEntryUpButton
Definition: InterfaceUnit.h:133
TInterface::RotateMenuItem
TMenuItem * RotateMenuItem
Definition: InterfaceUnit.h:435
TInterface::SpeedButton33
TSpeedButton * SpeedButton33
Definition: InterfaceUnit.h:536
TInterface::TTClockxSixteenthButtonClick
void __fastcall TTClockxSixteenthButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11666
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:588
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:505
TUtilities::Clock2Stopped
bool Clock2Stopped
when true the main loop - Interface->ClockTimer2 - is stopped
Definition: Utilities.h:38
TTrainController::MRSHigh
bool MRSHigh
Definition: TrainUnit.h:733
TInterface::FlipMenuItem
TMenuItem * FlipMenuItem
Definition: InterfaceUnit.h:433
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:5576
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:156
TInterface::SessionFileIntegrityCheck
bool SessionFileIntegrityCheck(int Caller, AnsiString FileName)
Checks session file integrity prior to loading, true for success.
Definition: InterfaceUnit.cpp:16848
TInterface::TrainFailedImage
TImage * TrainFailedImage
Definition: InterfaceUnit.h:479
TTrain::NotInService
bool NotInService
Definition: TrainUnit.h:428
TInterface::RotLeftMenuItemClick
void __fastcall RotLeftMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:9167
TInterface::SpeedButton14
TSpeedButton * SpeedButton14
Definition: InterfaceUnit.h:517
TInterface::ExitTrackButton
TBitBtn * ExitTrackButton
Definition: InterfaceUnit.h:75
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:641
TInterface::SpeedButton110
TSpeedButton * SpeedButton110
Definition: InterfaceUnit.h:613
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TInterface::OutputLog10
TLabel * OutputLog10
Definition: InterfaceUnit.h:300
TInterface::SESSION_DIR_NAME
static const UnicodeString SESSION_DIR_NAME
Definition: InterfaceUnit.h:864
TInterface::PasteTTEntryKeyFlag
bool PasteTTEntryKeyFlag
Definition: InterfaceUnit.h:1009
TInterface::FileChangedFlag
bool FileChangedFlag
true when a loaded railway file has changed (used to warn user if opts to exit without saving)
Definition: InterfaceUnit.h:940
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:141
TInterface::CutTTEntryButtonClick
void __fastcall CutTTEntryButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:3568
TInterface::AutoSigsButtonClick
void __fastcall AutoSigsButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:1980
TRailGraphics::SpeedBut69GrndBlackGlyph
Graphics::TBitmap * SpeedBut69GrndBlackGlyph
Definition: GraphicUnit.h:1046
Signaller
@ Signaller
Definition: TrainUnit.h:56
TRailGraphics::bmRedRect
Graphics::TBitmap * bmRedRect
Definition: GraphicUnit.h:526
TInterface::SaveOperatingImageMenuItemClick
void __fastcall SaveOperatingImageMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:2704
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TInterface::ConstructRoute
TOneRoute * ConstructRoute
the route under construction
Definition: InterfaceUnit.h:1123
TInterface::SpeedButton118
TSpeedButton * SpeedButton118
Definition: InterfaceUnit.h:621
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:8727
Bridge
@ Bridge
Definition: TrackUnit.h:63
TInterface::DirOpenError
bool DirOpenError
true when one of the program subfolders doesn't already exist and can't be created
Definition: InterfaceUnit.h:934
TInterface::CutMenuItemClick
void __fastcall CutMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8748
TInterface::SpeedButton38
TSpeedButton * SpeedButton38
Definition: InterfaceUnit.h:541
TInterface::ResetCurrentSpeedButton
void ResetCurrentSpeedButton(int Caller)
Resets the CurrentSpeedButton variable to zero and the 'Down' property to false.
Definition: InterfaceUnit.cpp:12663
TInterface::SpeedButton102
TSpeedButton * SpeedButton102
Definition: InterfaceUnit.h:605
TTrain::TimetableMaxRunningSpeed
double TimetableMaxRunningSpeed
the maximum train running speed when in timetable mode (see int SignallerMaxSpeed for signaller contr...
Definition: TrainUnit.h:381
TInterface::SpeedButton99
TSpeedButton * SpeedButton99
Definition: InterfaceUnit.h:602
clB0G0R0
#define clB0G0R0
Definition: GraphicUnit.h:36
TInterface::CPDeparturesCheckBox
TCheckBox * CPDeparturesCheckBox
Definition: InterfaceUnit.h:242
Buffers
@ Buffers
Definition: TrackUnit.h:63
TInterface::SelectGraphic
@ SelectGraphic
Definition: InterfaceUnit.h:880
TTextHandler::TextMove
void TextMove(int Caller, int HPosInput, int VPosInput, int &TextItem, int &TextMoveHPos, int &TextMoveVPos, bool &TextFoundFlag)
Definition: TextUnit.cpp:196
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
clFrontCodeTimetable
#define clFrontCodeTimetable
Definition: GraphicUnit.h:296
TTrack::UserGraphicPresentAtHV
bool UserGraphicPresentAtHV(int Caller, int HPos, int VPos, int &UGIVectorPos)
checks if a user graphic present
Definition: TrackUnit.h:734
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:9856
TInterface::ExitTTModeButtonClick
void __fastcall ExitTTModeButtonClick(TObject *Sender)
Definition: InterfaceUnit.cpp:4455
TInterface::MirrorMenuItemClick
void __fastcall MirrorMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:8842
TInterface::SpeedButton11
TSpeedButton * SpeedButton11
Definition: InterfaceUnit.h:514
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool ConsecSignalsRoute, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:13967
TInterface::SigPrefButton
TBitBtn * SigPrefButton
Definition: InterfaceUnit.h:195
TInterface::RouteNotStarted
@ RouteNotStarted
Definition: InterfaceUnit.h:885
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4029
TInterface::SaveImageAndGridMenuItem
TMenuItem * SaveImageAndGridMenuItem
Definition: InterfaceUnit.h:451
TInterface::SpeedButton48
TSpeedButton * SpeedButton48
Definition: InterfaceUnit.h:551
TInterface::WhiteBgndMenuItemClick
void __fastcall WhiteBgndMenuItemClick(TObject *Sender)
Definition: InterfaceUnit.cpp:11021